Daa Unit 1
Daa Unit 1
Unit I
An algorithm is a set of steps of operations to solve a problem performing calculation, data
processing, and automated reasoning tasks. An algorithm is an efficient method that can be
expressed within finite amount of time and space.
An algorithm is the best way to represent the solution of a particular problem in a very simple
and efficient way. If we have an algorithm for a specific problem, then we can implement it in
any programming language, meaning that the algorithm is independent from any programming
languages.
Algorithm Design
The important aspects of algorithm design include creating an efficient algorithm to solve a
problem in an efficient way using minimum time and space.
To solve a problem, different approaches can be followed. Some of them can be efficient with
respect to time consumption, whereas other approaches may be memory efficient. However,
one has to keep in mind that both time consumption and memory usage cannot be optimized
simultaneously. If we require an algorithm to run in lesser time, we have to invest in more
memory and if we require an algorithm to run with lesser memory, we need to have more time.
Characteristics of Algorithms
The main characteristics of algorithms are as follows −
• Algorithms must have a unique name
• Algorithms should have explicitly defined set of inputs and outputs
• Algorithms are well-ordered with unambiguous operations
• Algorithms halt in a finite amount of time. Algorithms should not run for infinity, i.e., an
algorithm must end at some point
Pseudocode
Pseudocode gives a high-level description of an algorithm without the ambiguity associated
with plain text but also without the need to know the syntax of a particular programming
language.
The running time can be estimated in a more general manner by using Pseudocode to represent
the algorithm as a set of fundamental operations which can then be counted.
Performance Analysis
we will discuss the need for analysis of algorithms and how to choose a better algorithm
for a particular problem as one computational problem can be solved by different algorithms.
By considering an algorithm for a specific problem, we can begin to develop pattern recognition
so that similar types of problems can be solved by the help of this algorithm.
Algorithms are often quite different from one another, though the objective of these algorithms
is the same. For example, we know that a set of numbers can be sorted using different
algorithms. Number of comparisons performed by one algorithm may vary with others for the
same input. Hence, time complexity of those algorithms may differ. At the same time, we need to
calculate the memory space required by each algorithm.
Analysis of algorithm is the process of analyzing the problem-solving capability of the algorithm
in terms of the time and size required (the size of memory for storage while implementation).
However, the main concern of analysis of algorithms is the required time or performance.
Generally, we perform the following types of analysis −
• Worst-case − The maximum number of steps taken on any instance of size a.
• Best-case − The minimum number of steps taken on any instance of size a.
• Average case − An average number of steps taken on any instance of size a.
• Amortized − A sequence of operations applied to the input of size a averaged over time.
Time Complexity
It’s a function describing the amount of time required to run an algorithm in terms of the
size of the input. "Time" can mean the number of memory accesses performed, the number of
comparisons between integers, the number of times some inner loop is executed, or some other
natural unit related to the amount of real time the algorithm will take.
Space Complexity
It’s a function describing the amount of memory an algorithm takes in terms of the size
of input to the algorithm. We often speak of "extra" memory needed, not counting the memory
needed to store the input itself. Again, we use natural (but fixed-length) units to measure this.
Space complexity is sometimes ignored because the space used is minimal and/or obvious,
however sometimes it becomes as important an issue as time.
Asymptotic Notations
Execution time of an algorithm depends on the instruction set, processor speed, disk I/O
speed, etc. Hence, we estimate the efficiency of an algorithm asymptotically.
Time function of an algorithm is represented by T(n), where n is the input size.
Different types of asymptotic notations are used to represent the complexity of an algorithm.
Following asymptotic notations are used to calculate the running time complexity of an
algorithm.
• O − Big Oh
• Ω − Big omega
• θ − Big theta
• o − Little Oh
• ω − Little omega
Big Oh Notation
Big-Oh (O) notation gives an upper bound for a function f(n) to within a constant factor.
We write f(n) = O(g(n)), If there are positive constants n0 and c such that, to the right of n0 the
f(n) always lies on or below c*g(n).
O(g(n)) = { f(n) : There exist positive constant c and n0 such that 0 ≤ f(n) ≤ c g(n), for all n ≤ n0}
Little o Notations
There are some other notations present except the Big-Oh, Big-Omega and Big-Theta
notations. The little o notation is one of them.
Little o notation is used to describe an upper bound that cannot be tight. In other words, loose
upper bound of f(n).
Let f(n) and g(n) are the functions that map positive real numbers. We can say that the function
f(n) is o(g(n)) if for any real positive constant c, there exists an integer constant n0 ≤ 1 such that
f(n) > 0.
For any value of n, the minimum time required by the algorithm is given by Omega Ω(g(n))
Master Theorem
The master method is a formula for solving recurrence relations of the form:
T(n) = aT(n/b) + f(n),
where,
n = size of input
a = number of subproblems in the recursion
n/b = size of each subproblem. All subproblems are assumed to have the same size.
f(n) = cost of the work done outside the recursive call, which includes the cost of di
viding the problem and cost of merging the solutions
Here, a ≥ 1 and b > 1 are constants, and f(n) is an asymptotically positive function
An asymptotically positive function means that for a sufficiently large value of n, we have
f(n) > 0.
The master theorem is used in calculating the time complexity of recurrence relations (divide
and conquer algorithms) in a simple and quick way.
T(n) = aT(n/b) + f(n),
where,
n = size of input
a = number of subproblems in the recursion
n/b = size of each subproblem. All subproblems are assumed to have the same size.
f(n) = cost of the work done outside the recursive call, which includes the cost of
dividing the problem and cost of merging the solutions
Here, a ≥ 1 and b > 1 are constants, and f(n) is an asymptotically positive function.
If a ≥ 1 and b > 1 are constants and f(n) is an asymptotically positive function, then the time
complexity of a recursive relation is given by
T(n) = 3T(n/2) + n2
Here,
a=3
n/b = n/2
f(n) = n2
logb a = log2 3 ≈ 1.58 < 2
ie. f(n) < nlogb a+ϵ , where, ϵ is a constant.
Master method is mainly derived from recurrence tree method. If we draw recurrence tree of
T(n) = aT(n/b) + f(n), we can see that the work done at root is f(n) and work done at all leaves is
Θ(nc) where c is Logba. And the height of recurrence tree is Logbn
In recurrence tree method, we calculate total work done. If the work done at leaves is
polynomially more, then leaves are the dominant part, and our result becomes the work done at
leaves (Case 1). If work done at leaves and root is asymptotically same, then our result becomes
height multiplied by work done at any level (Case 2). If work done at root is asymptotically
more, then our result becomes work done at root (Case 3).
Examples :
1. Solve the following recurrence relation using Master’s theorem-
T(n) = 3T(n/2) + n2
Sol:
We compare the given recurrence relation with T(n) = aT(n/b) + θ (nklogpn).
T(n) = θ (n2log0n)
Thus,
T(n) = θ (n2)
Thus,
T(n) = θ (nlog2n)
Solution- We compare the given recurrence relation with T(n) = aT(n/b) + θ (nklogpn).
Then, we have-a = 2,b = 4,k = 0.51,p = 0
Now, a = 2 and bk = 40.51 = 2.0279.
Clearly, a < bk.
So, we follow case-03.
Since p = 0, so we have-
T(n) = θ (n k logp n)
T(n) = θ (n0.51log0n)
Thus,
T(n) = θ (n0.51)
Solution-
We compare the given recurrence relation with T(n) = aT(n/b) + θ (nklogpn).
Then, we have-a = √2,b = 2,k = 0,p = 1
T(n) = θ (nlogba)
T(n) = θ (nlog2√2)
T(n) = θ (n1/2)
Thus,
T(n) = θ (√n)
Problem-05:
Now, a = 3 and bk = 31 = 3.
Clearly, a = bk.
Since p = 0, so we have-
T(n) = θ (nlogba.logp+1n)
T(n) = θ (nlog33.log0+1n)
T(n) = θ (n1.log1n)
Thus,
T(n) = θ (nlogn)
07:Form a recurrence relation for the following code and solve it using Master’s theorem-
A(n)
{
if(n<=1)
return 1;
else
return A(√n);
}
Solution-
We write a recurrence relation for the given code as T(n) = T(√n) + 1.
Here 1 = Constant time taken for comparing and returning the value.
We can not directly apply Master’s Theorem on this recurrence relation.
This is because it does not correspond to the general form of Master’s theorem.
However, we can modify and bring it in the general form to apply Master’s theorem.
Let-
n = 2m ……(1)
Then-
T(2m) = T(2m/2) + 1
Now, let T(2m) = S(m), then T(2m/2) = S(m/2)
So, we have-
S(m) = S(m/2) +1
Now, we can easily apply Master’s Theorem.
We compare the given recurrence relation with S(m) = aS(m/b) + θ (mklogpm).
Then, we have-
a = 1,b = 2,k = 0,p = 0
Now, a = 1 and bk = 20 = 1.
Clearly, a = bk.
So, we follow case-02.
Since p = 0, so we have-
S(m) = θ (mlogba.logp+1m)
S(m) = θ (mlog21.log0+1m)
S(m) = θ (m0.log1m)
Thus,
S(m) = θ(logm) ……(2)
Now,
From (1), we have n = 2m.
So, logn = mlog2 which implies m = log2n.
Substituting in (2), we get-
S(m) = θ(loglog2n)
Or
T(n) = θ (loglog2n)
DIVIDE-AND-CONQUER
In divide and conquer approach, the problem in hand, is divided into smaller sub-
problems and then each problem is solved independently. When we keep on dividing
the sub problems into even smaller sub-problems, we may eventually reach a stage
where no more division is possible. Those "atomic" smallest possible sub-problem
(fractions) are solved. The solution of all sub-problems is finally merged in order to
obtain the solution of an original problem.
Conquer/Solve
This step receives a lot of smaller sub-problems to be solved. Generally, at this level,
the problems are considered 'solved' on their own.
Merge/Combine
When the smaller sub-problems are solved, this stage recursively combines them until
they formulate a solution of the original problem. This algorithmic approach works
recursively and conquers & merges steps works so close that they appear as one.
Examples
The following computer algorithms are based on divide-and-conquer programming
approach
Merge Sort
Quick Sort
Binary Search
Strassen's Matrix Multiplication
There are various ways available to solve any computer problem, but the mentioned
are a good example of divide and conquer approach.
You can easily remember the steps of a divide-and-conquer algorithm as divide, conquer,
combine. Here's how to view one step, assuming that each divide step creates two sub
problems (though some divide-and-conquer algorithms create more than two):
The most recognizable benefit of the divide and conquer paradigm is that it allows us to
solve difficult problem, such as the Tower of Hanoi, which is a mathematical game or
puzzle. Being given a difficult problem can often be discouraging if there is no idea how
to go about solving it. However, with the divide and conquer method, it reduces the
degree of difficulty since it divides the problem into sub problems that are easily
solvable, and usually runs faster than other algorithms would.
It also uses memory caches effectively. When the sub problems become simple enough,
they can be solved within a cache, without having to access the slower main memory.
Time Complexity
The complexity of the divide and conquer algorithm is calculated using the
master theorem.
T(n) = a T(n/b) + f(n)
where,
n = size of input
a = number of sub problems in the recursion
n/b = size of each sub problem. All sub problems are assumed to have the same
size.
f(n) = cost of the work done outside the recursive call, which includes the cost of
dividing the problem and cost of merging the solutions
Binary Search
3. If the Pivot Element (the item to be searched) is less than the item in the middle of the
interval, We discard the second half of the list and recursively repeat the process for the
first half of the list by calculating the new middle and last element.
4. If the Pivot Element (the item to be searched) is greater than the item in the middle of
the interval, we discard the first half of the list and work recursively on the second half
by calculating the new beginning and middle element.
Now we compare the value stored at location 4, with the value being searched, i.e. 31.
We find that the value at location 4 is 27, which is not a match. As the value is greater
than 27 and we have a sorted array, so we also know that the target value must be in
the upper portion of the array.
We change our low to mid + 1 and find the new mid value again.
low = mid + 1
mid = low + (high - low) / 2
Our new mid is 7 now. We compare the value stored at location 7 with our target value
31.
The value stored at location 7 is not a match, rather it is more than what we are looking
for. So, the value must be in the lower part from this location.
VARUN MARAMRAJU 13
Unit -I
We compare the value stored at location 5 with our target value. We find that it is a
match.
o Find mid =
o Compare the search item with the mid item.
Case 1: item = A[mid], then LOC = mid, but it the best case and T (n) = 1
Case 2: item ≠A [mid], then we will split the array into two equal parts of size .
And again find the midpoint of the half-sorted array and compare with search element.
Repeat the same process until a search element is found.
{Time to compare the search element with mid element, then with half of the selected
half part of array}
At least there will be only one term left that's why that term will compare out, and only
Quick Sort
It is used on the principle of divide-and-conquer. Quick sort is an algorithm of choice in
many situations as it is not difficult to implement. It is a good general purpose sort and
it consumes relatively fewer resources during execution.
Quick sort works by partitioning a given array A[p ... r] into two non-empty sub
array A[p ... q] and A[q+1 ... r] such that every key in A[p ... q] is less than or equal to
every key in A[q+1 ... r].
Then, the two sub-arrays are sorted by recursive calls to Quick sort. The exact position
of the partition depends on the given array and index q is computed as a part of the
partitioning procedure.
if p < r then
qPartition (A, p, r)
Quick-Sort (A, p, q)
Quick-Sort (A, q + r, r)
Note that to sort the entire array, the initial call should be Quick-Sort (A, 1, length[A])
As a first step, Quick Sort chooses one of the items in the array to be sorted as
pivot. Then, the array is partitioned on either side of the pivot. Elements that are less
than or equal to pivot will move towards the left, while the elements that are greater
than or equal to pivot will move towards the right.
example
arr[] = {10, 80, 30, 90, 40, 50, 70}
Indexes: 0 1 2 3 4 5 6
arr[] = {10, 30, 40, 50, 80, 90, 70} // 90 and 50 Swapped
Now 70 is at its correct place. All elements smaller than 70 are before it and all
elements greater than 70 are after it.
Each possible Pivot P is selected with equal probability. The comparisons needed to do
is (N-1)
Now
T(N)=
=
Now multiply with ‘n’ on both sides, we get
N.T(N)=N.
2. ------------------ Equations (1)
Now consider N=N -1,then we get
(N-1).T(N-1)= 2.
Now consider
Analysis
Where as if partitioning leads to almost equal subarrays, then the running time is the
best, with time complexity as O(n*log n).
Worst Case Time Complexity [ Big- omega ]: Ω( (n2)
Best Case Time Complexity [Big-]: O(n*log n)
Space Complexity: O(n*log n)
Advantages
It is in-place since it uses only a small auxiliary stack.
It requires only n (log n) time to sort n items.
It has an extremely short inner loop.
This algorithm has been subjected to a thorough mathematical analysis, a very
precise statement can be made about performance issues.
Disadvantages
It is recursive. Especially, if recursion is not available, the implementation is
extremely complicated.
It requires quadratic (i.e., n2) time in the worst-case.
It is fragile, i.e. a simple mistake in the implementation can go unnoticed and
cause it to perform badly.
Merge Sort
Merge sort is one of the most efficient sorting algorithms. It works on the
principle of Divide and Conquer. Merge sort repeatedly breaks down a list into several
sublists until each sublist consists of a single element and merging those sublists in a
manner that results into a sorted list.
Divide the unsorted list into n sublists, each comprising 1 element (a list of 1 element is
supposed sorted).
Repeatedly merge sublists to produce newly sorted sublists until there is only 1 sublist
remaining. This will be the sorted list.
Iteration (2)
Iteration (3)
ALGORITHM-MERGE SORT
If p<r
Then q → ( p+ r)/2
MERGE-SORT (A, p, q)
MERGE-SORT ( A, q+1,r)
MERGE ( A, p, q, r)
But we ignore '-1' because the element will take some time to be copied in merge lists.
So T (n) = 2T + n...equation 1
Note: Stopping Condition T (1) =0 because at last, there will be only 1 element left that
need to be copied, and there will be no comparison.
=i
log2n=i
From 6 equation
Best Case Complexity: The merge sort algorithm has a best-case time complexity
of O(n*log n) for the already sorted array.
Average Case Complexity: The average-case time complexity for the merge sort
algorithm is O(n*log n), which happens when 2 or more elements are jumbled, i.e.,
neither in the ascending order nor in the descending order.
Worst Case Complexity: The worst-case time complexity is also O(n*log n), which occurs
when we sort the descending order of an array into the ascending order.
Space Complexity: The space complexity of merge sort is O(n).
Naïve Method
First, we will discuss naïve method and its complexity. Here, we are calculating Z = X ×
Y. Using Naïve method, two matrices (X and Y) can be multiplied if the order of these
matrices are p × q and q × r. Following is the algorithm.
Complexity
Here, we assume that integer operations take O(1) time. There are three for loops in this
algorithm and one is nested in other. Hence, the algorithm takes O(n3) time to execute.
This leads to a divide-and-conquer algorithm with running time T(n) = 7T(n/2) + _(n2)
Objective questions
(a) Central tendency (b) Differential equation (c) Order of execution (d) Order of
magnitude
Ans :Order of execution
32. Worst case efficiency of binary search is
(a) log2 n + 1 (b) n (c) N2 (d) 2n (e) log n.
Ans : log2 n + 1
33. For analyzing an algorithm, which is better computing time?
(a)O (100 Log N) (b) O (N) (c)O (2N) (d) O (N logN) (e) O (N2).
Ans :O (100 Log N)
34. What do you call the selected keys in the quick sort method?
(a) Outer key (b)Inner Key (c) Partition key(d) Pivot key (e) Recombine key.
Ans :c
35. The time complexity of the normal quick sort, randomized quick sort algorithms in
the worst case is
(a) O(n2), O(n log n) (b) O(n2), O(n2) (c) O(n log n), O(n2) (d) O(n log n), O(n log n)
Ans :O(n2), O(n2)
36. Let there be an array of length ‘N’, and the selection sort algorithm is used to sort it,
how many times a swap function is called to complete the execution?
(a) N log N times (b) log N times (c) N2 times (d) N-1 times
Ans :N-1 times
37. The Sorting methodwhich is used for external sort is
(a) Bubble sort (b) Quick sort (c) Merge sort (d) Radix sort
Ans :Radix sort
38. The amount of memory needs to run to completion is known as_____________
a. Space complexity c. Worst case
b. Time complexity d. Best case
Ans: Space complexity
39. The amount of time needs to run to completion is known as____________
a. Space complexity b. Time complexity c. Worst case d. Best case
Ans: Time complexity
40. __________ is the minimum number of steps that can executed for the given
parameters
a. Average case b. Time complexity c. Worst case d. Best case
Ans: Best case
41. __________ is the maximum number of steps that can executed for the given
parameters
a. Average case b. Time complexity c. Worst-case d. Best case
Ans:Worst case
42. __________ is the average number of steps that can executed for the given parameters
a. Average case b. Time complexity c. Worst case d. Best case
Ans: Average Case
43. Testing of a program consists of 2 phases which are
______________________and____________
a. Average case & Worst case b. Time complexity & Space complexity c.
Validation and checking errors d. Debugging and profiling
Ans: Debugging and profiling
44. Worst case time complexity of binary search is ______________
a. O(n) b. O(logn)c. Ɵ(nlogn) d. Ɵ(logn)
Ans: Ɵ(logn)
45. Best case time complexity of binary search is ______________
a. O(n) b. O(logn) c. Ɵ(nlogn) d. Ɵ(logn)
Ans: Ɵ(logn)
46. Average case time complexity of binary search is ______________
a. O(n) b. O(logn) c. Ɵ(nlogn) d. Ɵ(logn)
Ans: Ɵ(logn)
47. Merge sort invented by _____________
a. CARHOARE b. JOHN VON NEUMANN c. HAMILTON d. STRASSEN
Ans : JOHN VON NEUMANN
48. Quick sort invented by _____________
a. CARHOARE b. JOHN VON NEUMANN c. HAMILTON d. STRASSEN
Ans : CARHOARE
49. Worst case time complexity of Quick sort is ______________
a. O(n2log7) b. O(n2) c. O(nlogn) d. O(logn)
Ans : O(n2)
50. Best case time complexity of Quick sort is ______________
a. O(n2logn) b. O(logn) c. O(nlogn) d. O(logn2)
Ans : O(nlogn)
Previous Questions
10. Define recurrence equation? Find the time complexity of merge sort from recurrence relation
using substitution method.
11. Write the pseudo code for binary search and analyze the time complexity .
12. Explain the general method of divide and conquer with an example.
13. Explain the properties of algorithm with real time example.
14. Explain Recursive Binary search algorithm with suitable examples.
15. Distinguish between Merge sort and quick sort.
16. What is stable sorting method? Is Merge sort a stable sorting method? Justify your answer.
17. Explain partition exchange sort algorithm and trace this algorithm for n =8 elements: 24,12, 35,
23,45,34,20,48
18. Briefly explain merge sort algorithm with suitable example and derive its time complexity.
19. Explain divide and conquer in detail.
20. Show how quick sort sorts the following sequences of keys 65, 70, 75, 80, 85, 60, 55, 50, 45 solve
the recurrence relation of quick sort using substitution method.
21. Explain how divide and conquer method is used to implement Merge sort technique with its
Time complexity.
22. Write an algorithm for Quick sort.
23. Write Divide – And – Conquer recursive Quick sort algorithm and analyze the algorithm for
average time complexity.
24. Trace the quick sort algorithm to sort the list C, O, L, L, E, G, E in alphabetical orde r
25. Describe Strassen’s matrix multiplication. Perform the multiplication operation on following two
matrices using Strasen’s technique.
26. Write an algorithm for stressan’s matrix multiplication and analyze the complexity of your
Algorithm