0% found this document useful (0 votes)
12 views14 pages

Daa Notes

The document provides an introduction to algorithms, defining them as unambiguous instructions for problem-solving with specific characteristics such as input, output, definiteness, finiteness, and efficiency. It outlines the steps for writing algorithms, methods for specifying them, and emphasizes the importance of proving their correctness and analyzing their efficiency in terms of time and space. Additionally, it categorizes important problem types like sorting, searching, and graph problems, and discusses the fundamentals of analyzing algorithm efficiency.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views14 pages

Daa Notes

The document provides an introduction to algorithms, defining them as unambiguous instructions for problem-solving with specific characteristics such as input, output, definiteness, finiteness, and efficiency. It outlines the steps for writing algorithms, methods for specifying them, and emphasizes the importance of proving their correctness and analyzing their efficiency in terms of time and space. Additionally, it categorizes important problem types like sorting, searching, and graph problems, and discusses the fundamentals of analyzing algorithm efficiency.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

Design and Analysis

UNIT I INTRODUCTION
1.1 NOTION OF AN ALGORITHM

An algorithm is a sequence of unambiguous instructions for solving a problem, i.e., for


obtaining a required output for any legitimate input in a finite amount of time.

Problem to be solved

Algorithm

Input Computer Program Output

FIGURE 1.1 The notion of the algorithm.

It is a step-by-step procedure with the input to solve the problem in a finite amount of
timeto obtain the required output.

The notion of the algorithm illustrates some important points:


• The non-ambiguity requirement for each step of an algorithm cannot be compromised.
• The range of inputs for which an algorithm works must be specified carefully.
• The same algorithm can be represented in several different ways.
• There may exist several algorithms for solving the same problem.
• Algorithms for the same problem can be based on very different ideas and can solve the
problem with dramatically different speeds.

Characteristics of an algorithm:
Input: Zero / more quantities are externally supplied.
Output: At least one quantity is produced.
Definiteness: Each instruction is clear and unambiguous.
Finiteness: If the instruction of an algorithm is traced then for all cases the algorithm must
terminate after a finite number of steps.
Efficiency: Every instruction must be very basic and runs in a short time.
Steps for writing an algorithm:
1. An algorithm is a procedure. It has two parts; the first part is head and the second part is
body.
2. The Head section consists of keyword Algorithm and Name of the algorithm with
parameter list. E.g. Algorithm name1(p1, p2,…,p3)
The head section also has the following:
//Problem Description:
//Input:
//Output:
3. In the body of an algorithm various programming constructs like if, for, while and some
statements like assignments are used.
4. The compound statements may be enclosed with { and } brackets. if, for, while can be
closed by endif, endfor, endwhile respectively. Proper indention is must for block.
5. Comments are written using // at the beginning.
6. The identifier should begin by a letter and not by digit. It contains alpha numeric letters
after first letter. No need to mention data types.
7. The left arrow “←” used as assignment operator. E.g. v←10
8. Boolean operators (TRUE, FALSE), Logical operators (AND, OR, NOT) and Relational
operators (<,<=, >, >=,=, ≠, <>) are also used.
9. Input and Output can be done using read and write.
10. Array[], if then else condition, branch and loop can be also used in algorithm.

Example:
The greatest common divisor(GCD) of two nonnegative integers m and n (not-both-zero),
denoted gcd(m, n), is defined as the largest integer that divides both m and n evenly, i.e., with a
remainder of zero.

Euclid’s algorithm is based on applying repeatedly the equality gcd(m, n) = gcd(n, m mod n),
where m mod n is the remainder of the division of m by n, until m mod n is equal to 0. Since gcd(m,
0) = m, the last value of m is also the greatest common divisor of the initial m and n.
gcd(60, 24) can be computed as follows:gcd(60, 24) = gcd(24, 12) = gcd(12, 0) = 12.

Euclid’s algorithm for computing gcd(m, n) in simple steps


Step 1 If n = 0, return the value of m as the answer and stop; otherwise, proceed to Step 2.
Step 2 Divide m by n and assign the value of the remainder to r.
Step 3 Assign the value of n to m and the value of r to n. Go to Step 1.

Euclid’s algorithm for computing gcd(m, n) expressed in pseudocode


ALGORITHM Euclid_gcd(m, n)
//Computes gcd(m, n) by Euclid’s algorithm
//Input: Two nonnegative, not-both-zero integers m and n
//Output: Greatest common divisor of m and n
while n ≠ 0 do
r ←m mod n
m←n
n←r
return m
1.2 FUNDAMENTALS OF ALGORITHMIC PROBLEM SOLVING
A sequence of steps involved in designing and analyzing an algorithm is shown in the figure
below.

FIGURE 1.2 Algorithm design and analysis process.

(i) Understanding the Problem


• This is the first step in designing of algorithm.
• Read the problem’s description carefully to understand the problem statement completely.
• Ask questions for clarifying the doubts about the problem.
• Identify the problem types and use existing algorithms to find solution.
• Input (instance) to the problem and range of the input get fixed.

(ii) Decision making


The Decision making is done on the following:
(a) Ascertaining the Capabilities of the Computational Device
• In random-access machine (RAM), instructions are executed one after another (The
central assumption is that one operation at a time). Accordingly, algorithms
designed to be executed on such machines are called sequential algorithms.
• In some newer computers, operations are executed concurrently, i.e., in parallel.
Algorithms that take advantage of this capability are called parallel algorithms.
• Choice of computational devices like Processor and memory is mainly based on
space and time efficiency
(b) Choosing between Exact and Approximate Problem Solving
• The next principal decision is to choose between solving the problem exactly or
solving it approximately.
• An algorithm used to solve the problem exactly and produce correct result is called
an exact algorithm.
• If the problem is so complex and not able to get exact solution, then we must
choose an algorithm called an approximation algorithm. i.e., produces an
approximate answer. E.g., extracting square roots, solving nonlinear equations, and
evaluating definite integrals.
(c) Algorithm Design Techniques
• An algorithm design technique (or “strategy” or “paradigm”) is a general approach
to solving problems algorithmically that is applicable to a variety of problems from
different areas of computing.
• Algorithms+ Data Structures = Programs
• Though Algorithms and Data Structures are independent, they are combined
together to develop program. Hence the choice of proper data structure is required
before designing the algorithm.
• Implementation of algorithm is possible only with the help of Algorithms and Data
Structures
• Algorithmic strategy / technique / paradigm are a general approach by which
many problems can be solved algorithmically. E.g., Brute Force, Divide and
Conquer, Dynamic Programming, Greedy Technique and so on.

(iii) Methods of Specifying an Algorithm

There are three ways to specify an algorithm. They are:


a. Natural language
b. Pseudocode
c. Flowchart

Algorithm Specification

Natural Language Pseudocode Flowchart

FIGURE 1.3 Algorithm Specifications

Pseudocode and flowchart are the two options that are most widely used nowadays for specifying
algorithms.

a. Natural Language
It is very simple and easy to specify an algorithm using natural language. But many times
specification of algorithm by using natural language is not clear and thereby we get brief
specification.
Example: An algorithm to perform addition of two numbers.
Step 1: Read the first number, say a.
Step 2: Read the first number, say b.
Step 3: Add the above two numbers and store the result in c.
Step 4: Display the result from c.
Such a specification creates difficulty while implementing it. Hence many programmersprefer to
have specification of algorithm by means of Pseudocode.
b. Pseudocode
• Pseudocode is a mixture of a natural language and programming language constructs.
Pseudocode is usually more precise than natural language.
• For Assignment operation left arrow “←”, for comments two slashes “//”,if condition, for,
while loops are used.

ALGORITHM Sum(a,b)
//Problem Description: This algorithm performs addition of two numbers
//Input: Two integers a and b
//Output: Addition of two integers
c←a+b
return c
This specification is more useful for implementation of any language.

c. Flowchart
In the earlier days of computing, the dominant method for specifying algorithms was a flowchart,
this representation technique has proved to be inconvenient.
Flowchart is a graphical representation of an algorithm. It is a a method of expressing an algorithm
by a collection of connected geometric shapes containing descriptions of the algorithm’s steps.
Symbols Example: Addition of a and b

Start Start state


Start

Transition / Assignment
Input the value of a

Processing / Input read


Input the value of b
Input and Output
c=a+b

Condition / Decision
Display the value of c

Flow connectivity
Stop

Stop Stop state

FIGURE 1.4 Flowchart symbols and Example for two integer addition.

(iv) Proving an Algorithm’s Correctness

• Once an algorithm has been specified then its correctness must be proved.
• An algorithm must yield a required result for every legitimate input in a finite amount of
time.
• For example, the correctness of Euclid’s algorithm for computing the greatest common
divisor stems from the correctness of the equality gcd(m, n) = gcd(n, m mod n).
• A common technique for proving correctness is to use mathematical induction because an
algorithm’s iterations provide a natural sequence of steps needed for such proofs.
• The notion of correctness for approximation algorithms is less straightforward than it is for
exact algorithms. The error produced by the algorithm should not exceed a predefined
limit.

(v) Analyzing an Algorithm


• For an algorithm the most important is efficiency. In fact, there are two kinds of algorithm
efficiency. They are:
• Time efficiency, indicating how fast the algorithm runs, and
• Space efficiency, indicating how much extra memory it uses.
• The efficiency of an algorithm is determined by measuring both time efficiency and space
efficiency.
• So, factors to analyze an algorithm are:
▪ Time efficiency of an algorithm
▪ Space efficiency of an algorithm
▪ Simplicity of an algorithm
▪ Generality of an algorithm

(vi) Coding an Algorithm


• The coding / implementation of an algorithm is done by a suitable programming language
like C, C++, JAVA.
• The transition from an algorithm to a program can be done either incorrectly or very
inefficiently. Implementing an algorithm correctly is necessary. The Algorithm power
should not be reduced by inefficient implementation.
• Standard tricks like computing a loop’s invariant (an expression that does not change its
value) outside the loop, collecting common subexpressions, replacing expensive
operations by cheap ones, selection of programming language and so on should be known to
the programmer.
• Typically, such improvements can speed up a program only by a constant factor, whereas a
better algorithm can make a difference in running time by order of magnitude. But once an
algorithm is selected, a 10–50% speedup may be worth the effort.
• It is essential to write an optimized code (efficient code) to reduce the burden of compiler.

1.3 IMPORTANT PROBLEM TYPES


The most important problem types are:
(i). Sorting
(ii). Searching
(iii). String processing
(iv). Graph problems
(v). Combinatorial problems
(vi). Geometric problems
(vii). Numerical problems
(i) Sorting
• The sorting problem is to rearrange the items of a given list in nondecreasing (ascending)
order.
• Sorting can be done on numbers, characters, strings, or records.
• To sort student records in alphabetical order of names or by student number or by student
grade-point average. Such a specially chosen piece of information is called a key.
• An algorithm is said to be in-place if it does not require extra memory, E.g., Quick sort.
• A sorting algorithm is called stable if it preserves the relative order of any two equal
elements in its input.

(ii) Searching
• The searching problem deals with finding a given value, called a search key, in each set.
• E.g., Ordinary Linear search and fast binary search.

(iii) String processing


• A string is a sequence of characters from an alphabet.
• Strings comprise letters, numbers, and special characters; bit strings, which comprise zeros
and ones; and gene sequences, which can be modeled by strings of characters from the four-
character alphabet {A, C, G, T}. It is very useful in bioinformatics.
• Searching for a given word in a text is called string matching.

(iv) Graph problems


• A graph is a collection of points called vertices, some of which are connected by line
segments called edges.
• Some of the graph problems are graph traversal, shortest path algorithm, topological sort,
traveling salesman problem and the graph-coloring problem and so on.

(v) Combinatorial problems


• These are problems that ask, explicitly or implicitly, to find a combinatorial object such as a
permutation, a combination, or a subset that satisfies certain constraints.
• A desired combinatorial object may also be required to have some additional property such
as a maximum value or a minimum cost.
• In practical, the combinatorial problems are the most difficult problems in computing.
• The traveling salesman problem and the graph coloring problem are examples of
combinatorial problems.

(vi) Geometric problems


• Geometric algorithms deal with geometric objects such as points, lines, and polygons.
• Geometric algorithms are used in computer graphics, robotics, and tomography.
• The closest-pair problem and the convex-hull problem come under this category.
(vii) Numerical problems
• Numerical problems are problems that involve mathematical equations, systems of
equations, computing definite integrals, evaluating functions, and so on.
• Most of such mathematical problems can be solved only approximately.
1.4 FUNDAMENTALS OF THE ANALYSIS OF ALGORITHM EFFICIENCY
The efficiency of an algorithm can be in terms of time and space. The algorithm efficiency
can be analyzed in the following ways.
a. Analysis Framework.
b. Asymptotic Notations and their properties.
c. Mathematical analysis for Recursive algorithms.
d. Mathematical analysis for non-recursive algorithms.

1.5 Analysis Framework


There are two kinds of efficiencies to analyze the efficiency of any algorithm. They are:
• Time efficiency, indicating how fast the algorithm runs, and
• Space efficiency, indicating how much extra memory it uses.

The algorithm analysis framework consists of the following:


• Measuring an Input’s Size
• Units for Measuring Running Time
• Orders of Growth
• Worst-Case, Best-Case, and Average-Case Efficiencies

(i) Measuring an Input’s Size


• An algorithm’s efficiency is defined as a function of some parameter n indicating the
algorithm’s input size. In most cases, selecting such a parameter is quite straightforward.
For example, it will be the size of the list for problems of sorting and searching.
• For the problem of evaluating a polynomial p(x) = anxn + . . . + a0 of degree n, the size of
the parameter will be the polynomial’s degree or the number of its coefficients, which is
larger by 1 than its degree.
• In computing the product of two n × n matrices, the choice of a parameter indicating an
input size does matter.
• Consider a spell-checking algorithm. If the algorithm examines individual characters of its
input, then the size is measured by the number of characters.
• In measuring input size for algorithms solving problems such as checking primality of a
positive integer n. the input is just one number.
• The input size by the number b of bits in the n’s binary representation is b=(log2 n)+1.

(ii) Units for Measuring Running Time


Some standard unit of time measurement such as a second, or millisecond, and so on can be
used to measure the running time of a program after implementing the algorithm.
Drawbacks
• Dependence on the speed of a particular computer.
• Dependence on the quality of a program implementing the algorithm.
• The compiler is used in generating machine code.
• The difficulty of clocking the actual running time of the program.
So, we need metric to measure an algorithm’s efficiency that does not depend on these
extraneous factors.
One possible approach is to count the number of times each of the algorithm’s operations
is executed. This approach is excessively difficult.
The most important operation (+, -, *, /) of the algorithm, is called the basic operation.
Computing the number of times, the basic operation is executed is easy. The total running time is
determined by basic operations count.
(iii) Orders of Growth
• A difference in running times on small inputs is not what really distinguishes efficient
algorithms from inefficient ones.
• For example, the greatest common divisor of two small numbers, it is not immediately clear
how much more efficient Euclid’s algorithm is compared to the other algorithms, the
difference in algorithm efficiencies becomes clear for larger numbers only.
• For large values of n, it is the function’s order of growth that counts just like the Table 1.1,
which contains values of a few functions particularly important for analysis of algorithms.

TABLE 1.1 Values (approximate) of several functions important for analysis of algorithms

n √𝑛 log2n n n log2n n2 n3 2n n!
1 1 0 1 0 1 1 2 1
2 1.4 1 2 2 4 4 4 2
4 2 2 4 8 16 64 16 24
8 2.8 3 8 2.4•101 64 5.1•102 2.6•102 4.0•104
10 3.2 3.3 10 3.3•101 102 103 103 3.6•106
16 4 4 16 6.4•101 2.6•102 4.1•103 6.5•104 2.1•1013
102 10 6.6 102 6.6•102 104 106 1.3•1030 9.3•10157
103 31 10 103 1.0•104 106 109
104 102 13 104 1.3•105 108 1012 Very big
105 3.2•102 17 105 1.7•106 1010 1015 computation
106 103 20 106 2.0•107 1012 1018

(iv) Worst-Case, Best-Case, and Average-Case Efficiencies


Consider Sequential Search algorithm some search key K
ALGORITHM SequentialSearch(A[0..n - 1], K)
//Searches for a given value in a given array by sequential search
//Input: An array A[0..n - 1] and a search key K
//Output: The index of the first element in A that matches K or -1 if there are no
// matching elements
i ←0
while i < n and A[i] ≠ K do
i ←i + 1
if i < n return i
else return -1
Clearly, the running time of this algorithm can be quite different for the same list size n.

In the worst case, there is no matching of elements or the first matching element can found
at last on the list. In the best case, there is matching of elements at first on the list.

Worst-case efficiency
• The worst-case efficiency of an algorithm is its efficiency for the worst case input of size n.
• The algorithm runs the longest among all possible inputs of that size.
• For the input of size n, the running time is Cworst(n) = n.
Best case efficiency
• The best-case efficiency of an algorithm is its efficiency for the best case input of size n.
• The algorithm runs the fastest among all possible inputs of that size n.
• In sequential search, If we search a first element in list of size n. (i.e. first element equal to
a search key), then the running time is Cbest(n) = 1

Average case efficiency


• The Average case efficiency lies between best case and worst case.
• To analyze the algorithm’s average case efficiency, we must make some assumptions about
possible inputs of size n.
• The standard assumptions are that
o The probability of a successful search is equal to p (0 ≤ p ≤ 1) and
o The probability of the first match occurring in the ith position of the list is the same
for every i.

Yet another type of efficiency is called amortized efficiency. It applies not to a single run of
an algorithm but rather to a sequence of operations performed on the same data structure.

1.6 ASYMPTOTIC NOTATIONS AND ITS PROPERTIES

Asymptotic notation is a notation, which is used to take meaningful statement about the
efficiency of a program.
The efficiency analysis framework concentrates on the order of growth of an algorithm’s
basic operation count as the principal indicator of the algorithm’s efficiency.
To compare and rank such orders of growth, computer scientists use three notations, they
are:
• O - Big oh notation
• Ω - Big omega notation
• Θ - Big theta notation
Let t(n) and g(n) can be any nonnegative functions defined on the set of natural numbers.
The algorithm’s running time t(n) usually indicated by its basic operation count C(n), and g(n),
some simple function to compare with the count.

Example 1:

where g(n) = n2.


(i) O - Big oh notation
A function t(n) is said to be in O(g(n)), denoted 𝑡 (𝑛) ∈ 𝑂(𝑔(𝑛)), if t (n) is bounded above
by some constant multiple of g(n) for all large n, i.e., if there exist some positive constant c and
some nonnegative integer n0 such that
𝑡 (𝑛) ≤ 𝑐𝑔(𝑛) fo𝑟 𝑎𝑙𝑙 𝑛 ≥ 𝑛0.
Where t(n) and g(n) are nonnegative functions defined on the set of natural numbers.
O = Asymptotic upper bound = Useful for worst case analysis = Loose bound

FIGURE 1.5 Big-oh notation: 𝑡 (𝑛) ∈ 𝑂(𝑔(𝑛)).

Example 2: Prove the assertions 100𝑛 + 5 ∈ 𝑂(𝑛2).


Proof: 100n + 5 ≤ 100n + n (for all n ≥ 5)
= 101n
≤ 101n2 (Ӭ 𝑛 ≤ 𝑛2)
Since, the definition gives us a lot of freedom in choosing specific values for constants c
and n0. We have c=101 and n0=5
Example 3: Prove the assertions 100𝑛 + 5 ∈ 𝑂(𝑛).
Proof: 100n + 5 ≤ 100n + 5n (for all n ≥ 1)
= 105n
i.e., 100n + 5 ≤ 105n
i.e., t(n) ≤ cg(n)
±100𝑛 + 5 ∈ 𝑂(𝑛) with c=105 and n0=1

(ii) Ω - Big omega notation


A function t(n) is said to be in Ω(g(n)), denoted t(n) ∈ Ω(g(n)), if t(n) is bounded below by
some positive constant multiple of g(n) for all large n, i.e., if there exist some positive constant c
and some nonnegative integer n0 such that
t (n) ≥ cg(n) for all n ≥ n0.
Where t(n) and g(n) are nonnegative functions defined on the set of natural numbers.
Ω = Asymptotic lower bound = Useful for best case analysis = Loose bound
FIGURE 1.6 Big-omega notation: t (n) ∈ Ω (g(n)).

Example 4: Prove the assertions n3+10n2+4n+2 ∈ Ω (n2).


Proof: n3+10n2+4n+2 ≥ n2 (for all n ≥ 0)
i.e., by definition t(n) ≥ cg(n), where c=1 and n0=0

(iii) Θ - Big theta notation


A function t(n) is said to be in Θ(g(n)), denoted t(n) ∈ Θ(g(n)), if t(n) is bounded both above
and below by some positive constant multiples of g(n) for all large n, i.e., if there exist some
positive constants c1 and c2 and some nonnegative integer n0 such that
c2g(n) ≤ t (n) ≤ c1g(n) for all n ≥ n0.
Where t(n) and g(n) are nonnegative functions defined on the set of natural numbers.
Θ = Asymptotic tight bound = Useful for average case analysis

FIGURE 1.7 Big-theta notation: t (n) ∈ Θ(g(n)).

1
Example 5: Prove the assertions 𝑛 (𝑛 − 1) ∈ Θ(𝑛2).
2
Proof: First prove the right inequality (the upper bound):
1 𝑛 (𝑛 − 1) = 1 𝑛2 − 1 𝑛 ≤ 1 𝑛2 for all n ≥ 0.
2 2 2 2
Second, we prove the left inequality (the lower bound):
1 𝑛 (𝑛 − 1) = 1 𝑛2 − 1 𝑛 ≥ 1 𝑛2 − [1 𝑛] [1 𝑛] for all n ≥ 2.
2 2 2 2 2 2
± 1𝑛 (𝑛 − 1) ≥ 1 𝑛2
2 4
1
i.e., 𝑛2 ≤ 1 𝑛 (𝑛 − 1) ≤ 1 𝑛2
4 2 2
1
Hence,
1 𝑛 (𝑛 − 1) ∈ Θ(𝑛 )2 1

2
, where c2= 4 , c1= 2 and n0=2

Note: asymptotic notation can be thought of as "relational operators" for functions like the
corresponding relational operators for values.
= ⇒ Θ(), ≤ ⇒ O(), ≥ ⇒ Ω(), < ⇒ o(), > ⇒ ω()

You might also like