ADA Unit-2
ADA Unit-2
Selection Sort
Scan the entire given list to find its smallest element and exchange it
with the first element, putting the smallest element in its final position in
the sorted list.
Then, scan the list, starting with the second element, to find the smallest
among the last n-1 elements and exchange it with the second element,
putting the second smallest element in its final position.
Generally, on the ith pass through the list, the algorithm searches for the
smallest item among the last n-i elements and swaps it with Ai
ALGORITHM SelectionSort(A[0…n-1])
//Sorts a given array by selection sort
//Input: An array A[0…n-1] of orderable elements
//Output: Array A[0…n-1] sorted in ascending order
for i ← 0 to n-2 do
min ← i
for j ← i + 1 to n-1 do
if A[j] < A[min] min ← j
swap A[i] and A[min]
Basic operation:
Key comparison
Bubble Sort
Compare adjacent elements of the list and exchange them if they are out
of order. This is done repeatedly till the end of the list.
After first pass, the largest element will be placed in the last position in
the list. The next pass bubbles up the second largest element, and so on.
After n-1 passes, the list is sorted.
Pass i (0 ≤ i ≤ n-2) of the bubble sort can be represented by the following
diagram:
?
A0, . . . , Aj ↔ Aj+1, . . . , An-i-1 | An-i ≤ . . . ≤ An-1
in their final positions
ALGORITHM BubbleSort(A[0…n-1])
//Sorts a given array by bubble sort
//Input: An array A[0…n-1] of orderable elements
//Output: Array A[0…n-1] sorted in ascending order
for i ← 0 to n-2 do
for j ← 0 to n – 2 - i do
if A[j + 1] < A[j] swap A[i] and A[j + 1]
Basic operation:
Key comparison
n-2 n-2
= ∑ [(n - 2- i ) - 0 + 1] = ∑ (n – 1 - i)
i=0 i=0
= n(n-1) Є Θ(n2)
2
Example: Sort {89, 68, 45, 20} in ascending order using Bubble sort.
89 ↔ 68 45 20
68 89 ↔ 45 20
68 45 89 ↔ 20
68 45 20 89
PASS 0
68 ↔ 45 20 89
45 68 ↔ 20 89
45 20 68 89
PASS 1
45 ↔ 20 68 89
PASS 2
20 45 68 89
Sequential Search
ALGORITHM SequentialSearch(A[0…n], k)
//Implements sequential search with a search key as a sentinel
//Input: An array A of n elements and a search key K
//Output: The index of the first element in A[0…n-1] whose value is
// equal to K or -1 if no such element is found
A[n] ← K
i ←0
while i<n and A[i] ≠ K do
i ← i+1
if i < n return i
else return -1
Align the pattern against the first m characters of the text and start
matching the corresponding pairs of characters from left to right until all
m pairs of the characters match ( then the algorithm can stop) or a
mismatching pair is encountered.
If a mismatch pair is encountered, then shift the pattern one position to
the right and resume character comparisons, starting again with the first
character of the pattern and its counterpart in the text.
Smt. Kavitha M, Assistant professor, Dept. of CSE, SIT, Tumkur-3 Page 5
Analysis and Design of Algorithms – Unit - 2
Note that the last position in the text which can still be a beginning of a
matching substring is n – m (provided text’s positions are indexed from 0
to n – 1).
Basic operation:
Key comparison
The number of times the basic operation is executed depends not only
on the array size but also on pattern of input.
n-m m-1 n-m n-m
Cworst(n) = ∑ ∑1 = ∑ [(m - 1) - 0 + 1] = ∑ m.
i=0 j=0 i=0 i=0
n-m
=m ∑ 1 = m ((n - m) – 0 + 1) = mn – m2 + m
i=0
≈ mn Є Θ(mn)
Cbest(n) = Θ(m)
Divide-and-Conquer Technique
where, f (n) is a function that accounts for the time spent on dividing the
problem into smaller ones and on combining their solutions.
Master Theorem:
Θ(nd) if a < bd
Θ(nlogba) if a > bd
Mergesort
The strategy behind Merge Sort is to change the problem of sorting into
the problem of merging two sorted sub-arrays into one.
If the two halves of the array were sorted, then merging them carefully
could complete the sort of the entire array.
Mergesort sorts a given array A[0…n-1] by dividing it into two halves
A[0… n/2 -1] and A[ n/2 …n-1], sorting each of them recursively, and
then merging the two smaller sorted arrays into a single sorted one.
The merging of two sorted arrays can be done as follows:
Two pointers (array indices) are initialized to point to the first
elements of the arrays being merged.
The elements pointed to are compared, and the smaller of them is
added to a new array being constructed.
After that, the index of the smaller element is incremented to point
to its immediate successor in the array it was copied from.
This operation is repeated until one of the two given arrays is
exhausted, and then the remaining elements of the other array are
copied to the end of the new array.
Mergesort Algorithm
ALGORITHM Mergesort(A[0…n-1])
//Sorts array A[0…n-1] by recursive mergesort
//Input: An array A[0…n-1] of orderable elements
//Output: Array A[0…n-1] sorted in nondecreasing order
if n > 1
copy A[0 . . . n/2 - 1] to B[0 . . . n/2 - 1]
copy A[ n/2 . . . n - 1] to C[0 . . . n/2 – 1]
Mergesort(B[0 . . . n/2 – 1])
Mergesort(C[0 . . . n/2 – 1])
Merge(B, C, A)
For the worst case (Ex: smaller elements may come from the alternating
arrays), Cmerge(n) = n – 1, and we have the recurrence
Cworst(n) = 2Cworst(n/2) + n – 1 for n > 1, Cworst(1) = 0.
Quicksort
After a partition has been achieved, A[s] will be in its final position in
the sorted array.
We can continue sorting the two subarrays of the elements preceding
and following A[s] independently by using same method.
Smt. Kavitha M, Assistant professor, Dept. of CSE, SIT, Tumkur-3 Page 12
Analysis and Design of Algorithms – Unit - 2
Quicksort Algorithm
ALGORITHM Quicksort(A[l..r])
//Sorts a subarray by quicksort
//Input: A subarray A[l..r] of A[0..n - 1], defined by its left and right indices l and r
//Output: The subarray A[l..r] sorted in nondecreasing
//order
if l < r
s Partition(A[l...r]) //s is a split position
Quicksort(A[l...s - 1])
Quicksort(A[s + 1…r])
ALGORITHM Partition(A[l..r])
//Partitions a subarray by using its first element as a pivot
//Input: subarray A[l..r] of A[0..n - 1], defined by its left
//and right indices l and r (l< r)
//Output: A partition of A[l..r], with the split position
//returned as this function’s value
p A[l]
i l; j r+1
repeat
repeat i i + 1 until A[i] ≥ p or i ≥ r
repeat j j – 1 until A[j] ≤ p
swap(A[i], A[j ])
until i ≥ j
swap(A[i],A[j]) // undo last swap when i ≥ j
swap(A[l], A[j ])
return j
Left-to-Right Scan:
The left-to-right scan, denoted by index i, starts with the second element.
Since we want elements smaller than the pivot to be in the first part of
the subarray, this scan skips over elements that are smaller than the
pivot and stops on encountering the first element greater than or
equal to the pivot.
Right-to-Left Scan:
The right-to-left scan, denoted by index j, starts with the last element of
the subarray.
Since we want elements larger than the pivot to be in the second part of
the subarray, this scan skips over elements that are larger than the pivot
and stops on encountering the first element smaller than or equal to
the pivot.
After both scans stop, three situations may arise, depending on whether
or not the scanning indices have crossed:
1. If scanning indices i and j have not crossed, i.e., i < j, we simply
exchange A[i] and A[j] and resume the scans by incrementing i and
decrementing j, respectively:
2. If the scanning indices have crossed over, i.e., i > j, we will have
partitioned the array after exchanging the pivot with A[j]:
3. Finally, if the scanning indices stop while pointing to the same element,
i.e., i=j, the value they are pointing to must be equal to p. Thus we have
the array partitioned, with the split position s = i = j :
We can combine the case i=j with the case of crossed-over indices (i>j) by
exchanging the pivot with A[j] whenever i ≥ j.
Example: Draw the tree structure of the recursive calls made to sort the list
{40, 20, 10, 80, 60, 50, 7, 30, 100} in ascending order using Quicksort.
Therefore, the number of key comparisons in the best case will satisfy
the recurrence:
In the worst case, all the splits will be skewed to the extreme: one of the
two subarrays will be empty, while the size of the other will be just one
less than the size of the subarray being partitioned. This situation arises
in particular, for increasing arrays (already Sorted).
If A[0 . . . n-1] is a strictly increasing array and we use A[0] as the pivot,
the left-to-right scan will stop on A[1] while the right-to-left scan will go
all the way to reach A[0], indicating the split at position 0:
This sorting continues until the last one A[n-2] . . . n-1] has been
processed. The total number of key comparisons made will be equal to
Binary Search
Binary Search is an efficient algorithm for searching in a sorted array.
The basic algorithm is to find the middle element of the list, compare it
against the key, decide which half of the list must contain the key, and
repeat with that half.
Worst-Case Analysis:
For simplicity we assume that after one comparison of K with A[m], the
algorithm can determine whether K is smaller, equal to, or larger than
A[m].
The worst-case inputs include all arrays that do not contain a given
search key.
Since after one comparison the algorithm faces the same situation but
for an array half the size, we get the following recurrence relation for
Cworst(n):
Cworst (n) = Cworst( n/2 )+1 for n > 1, Cworst(1) = 1
Average-Case Analysis: