Algorithm: Design and Analysis: Sorting Problem
Algorithm: Design and Analysis: Sorting Problem
Sorting Problem
Dr. Khaled W. Mahmoud
1
1- Quick Sort
Idea:
◦ Partition a given elements into two sets such that the smaller
numbers into one set and larger number into another.
This partition is done with respective an element called pivot.
◦ Repeat the process for both the sets until each partition
contains only one element.
2
Quick Sort: Algorithm
void QuickSort (int A[], int low, int high){
int pivotPoint = partition(A, low, high);
if (low < pivotPoint ) QuickSort(A, low, pivotPoint-1);
if (high > pivotPoint) QuickSort(A, pivotPoint+1, high);
}
Quick Sort: Algorithm
int partition(int A[], int low, int high){
int pivot=A[low];
while (low < high) {
while ((A[high]>pivot) && (low < high)) high=high-1;
if (low != high) {
A[low]=A[high];
low=low+1;
}
while ((A[low]<pivot)&& (low < high)) low=low+1;
if (low != high){
A[high]=A[low];
high=high-1;
}
}// end while
A[high]=pivot;
return high;
}
4
Quick Sort: Example
#of DC = 21
5
Quick Sort: Partition Analysis
Partition algorithm compare each key to pivot, so if
there are n positions in the range of the array its
working on, it does n-1 key comparisons.
◦ O(n): blind.
Quick Sort: Analysis
Worst-case (DC): when partition split
the range into
1. empty sub-range (key smaller than pivot)
2. a sub-range with k-1 element.
◦ This happens when the array is sorted or in
reversed order.
W(n) = n(n-1)/2 O (n2)
A(n) 1.386nlgn-2.846n
7
Quick Sort: Analysis
Best case (DC): Suppose that
each partition split the range
into two equal sub-ranges, then
◦ then log2(N) levels of recursive
calls.
◦ The whole array is scanned at each
level of calls, so the total work
done is O(N*log(N)).
This is the upper limit
8
How many DC?
9
Quick Sort: Space usage
Explicitly:
◦ It is “in-place” sort, as no extra array is needed.
Implicitly:
◦ there are hidden space usage: stacks for recursive calls
◦ The memory needed for the original array and the stack frame
memory is n + (depth of the call graph)
◦ The size of the recursive stack depends on the number of sub-ranges
into which the range will be split.
The worst case:
◦ If partition split off one entry at a time, the depth of recursion is n,
and in each stack frame the array is reserved i.e. W(n) (n)
The average case = log(n)
Quick Sort: Improvements
1- Choice of Pivot
QSort works well if the pivot belong near the middle of the segment.
Choosing E[First] as a pivot causes QSort to do poorly in cases where
sorting should be easily.
Several strategies for choosing pivot:
◦ Choose a random key.
◦ let pivot be the median of the E[First], E[last] and E[(first+last)/2)]
In either case the selected pivot should be move to E[First].
The main idea is to split the range into two equal sub range.
Quick Sort: Improvements
2- Small Sort
Whenever the size of a subset is small, QSort become inefficient.
this can be improved by using simple, non-recursive sort algorithm for
small subset i.e.:
if (L-f >=small size)
--
else
smallsort(E,f,l)
3- Stack-space Optimization:
The second recursive call in the last statement can be converted into
iteration.
Avoid making the recursive call on the larger sub-range.
2- Merge Sort
Idea: It split input array in two halves, calls itself for
the two halves and then merges the two sorted halves.
Merge Sort: Merging Sorted Sequences
Problem: Given two sequences A and B sorted in non-
decreasing order, merge them to create one sorted
sequence C.
Strategy:
second array.
Assuming that both arrays are equal (i.e. n/2) then
Space Usage:
Merging sorted sequence with a total of n entries (k+m) requires enough memory
Worst case DC: Test the above analysis using array of size 9
Merge Sort: Analysis
Merge Sort is not in-place sort :
◦ Extra space used in merge W(n) (n)
◦ Stack is used for recursion: W(n) ( log n)
◦ Total (n)
However, the amount of extra space needed can be
decreased:
If A and B are linked list and they are not needed after the
merge is completed , then the nodes can be recycled as C is
created.
If k>=m and A has room for n=k + m, then the extra m
locations in A are needed (i.e. do merging from the right ends).
Merge Sort: Analysis
Note:
Merge Sort does about 30% fewer comparisons in the
worst case than quick sort does in the average.
However, merge sort does more elements movement than
QSort.
26
Heap Sort : fixHeap (heapify)
Input: an array A and an index i.
◦ Assumption: sub-trees rooted in Left(i) and Right(i) are proper
max-heaps, but A[i] may be smaller than its children
Output: heap that full fill all requirements
…
void fixHeap(int A[],int index,int n){
int j=2*index+1;
while ( j < n ){
if ( j+1 < n ){if ( A[j] < A[j+1] )j++; }
if ( A[index] < A[j] ){
int t=A[index]; A[index]=A[j]; A[j]=t;
index=j; j=2*index+1;
}
else
break;
}}
28
FixHeap (Recursive)
void fixHeapR(int E[], int root, int heapSize) {
int k=E[root];int largerSubHeap;
int left=2*root+1, right = 2*root+2;
if (left>= heapSize)// Root is a leaf
E[root] = k;
else{ //Root has left child
if (right>=heapSize)
largerSubHeap=left; //Root has left child only
else if (E[left] > E[right]) //Root has both left and right children
largerSubHeap = left;
else
largerSubHeap = right;
if (k>= E[largerSubHeap])
E[root]=k;
else{
E[root] = E[largerSubHeap];
E[largerSubHeap]=k;
fixHeapR(E, largerSubHeap, heapSize);
} }}
Heap Sort: Construct (build) Heap
Input: A heap structure H that does not necessarily
have the partial order tree property
Output: H with the same nodes rearranged to satisfy
31
Heap Sort: Construct (build) Heap (Recursive)
S= sortH (H)
Sorted Array: S
Heap Sort: Example
Given an array of 6 elements: 15, 19, 10, 7, 17, 16, sort
it in ascending order using heap sort.
after construct
34
…
Delete 19:
◦ Swap 19 with 10 (last
element)
◦ Exclude 19 from the array
(n--)
◦ Fix the root (10)
Delete 17 …
Delete 16 …
Delete 15 …
Delete 10 ….
35
Heap Sort: delete Max (sort heap)
void sortH(int A[], int n){
int y=n-1;
while( y>0 ){
int t=A[0];
A[0]=A[y];
A[y]=t;
y--;
n--;
fixHeap(A,0,n);
}
}
Heap Sort: Complexity Analysis
For Space:
in-place algorithm for iterative algorithms.
The depth of recursive (if used) is about lgn.
For Time:
First: FixHeap… DC
Requires 2h comparisons of keys in the worst case on a
heap with height h.
h = Floor(log n) // for example: if n= 15, then h=log 15= 3.xx
W(n) 2 lg(n)
Heap Sort: Complexity Analysis
Second: construct Heap … DC
Let r be the number of nodes in the right sub tree
W(n) = W(const: left side)+ W(const: right tree)+ fixheap
40
Finally: Optimality
Theorem:
Any algorithm to sort n items by comparisons must do
at least
◦ in worst case
n log n 1.443n
Solve(I)
if (size(I) <= small-size)
solution = directly-Solve(I);
else
divide I into I1, …, Ik.
for each i in {1, …, k}
Si = solve(Ii);
solution = combine(S1, …, Sk);
return solution;
Divide & Conquer Algorithms:
To describe the amount of work done by an algorithm:
for n>small size:
◦ T(n)=D(n)+∑T(size(Ii))+C(n) ; where
D(n): steps done by divide
T(n): steps done small instance
C(n): steps done combine
for n<=small size:
◦ T(n)=B(n) ; Done by direct solve
Example: Quicksort
Divide
◦ Partition the array A into 2 subarrays, such that each
element of A[p..q-1] is smaller than each element in
A[q+1..r]
◦ The index (pivot) q is computed
Conquer
◦ Recursively sort A[p..q-1] and A[q+1..r] using Quicksort
Combine
◦ Trivial: the arrays are sorted in place no work needed to
combine them: the entire array is now sorted
Example: Merge sort
Divide
◦ Divide the n-element sequence to be sorted into
two subsequences of n/2 elements each
Conquer
◦ Sort the subsequences recursively using merge sort
◦ When the size of the sequences is 1 there is
nothing more to do
Combine
◦ Merge the two sorted subsequences