210 likes | 354 Views
§5 Heapsort. Algorithm 1: { BuildHeap( H ); for ( i=0; i<N; i++ ) TmpH[ i ] = DeleteMin( H ); for ( i=0; i<N; i++ ) H[ i ] = TmpH[ i ]; }. /* O( N ) */. /* O( log N ) */. /* O( 1 ) */. T ( N ) = O ( N log N ). The space requirement is doubled. 1/21.
E N D
§5 Heapsort Algorithm 1: { BuildHeap( H ); for ( i=0; i<N; i++ ) TmpH[ i ] = DeleteMin( H ); for ( i=0; i<N; i++ ) H[ i ] = TmpH[ i ]; } /* O( N ) */ /* O( log N ) */ /* O( 1 ) */ T( N ) = O ( N log N) The space requirement is doubled. 1/21
§5 Heapsort b A [0] [1] d a [2] c [3] Algorithm 2: void Heapsort( ElementType A[ ], int N ) { int i; for ( i = N / 2; i >= 0; i - - ) /* BuildHeap */ PercDown( A, i, N ); for ( i = N - 1; i > 0; i - - ) { Swap( &A[ 0 ], &A[ i ] ); /* DeleteMax */ PercDown( A, 0, i ); } } c d b a b a b a b c c d b Heapsort data start from position 0. 【Theorem】The average number of comparisons used to heapsort a random permutation of N distinct items is 2N log N O(N log log N) . Note: Although Heapsort gives the best average time, in practice it is slower than a version of Shellsort that uses Sedgewick’s increment sequence. 2/21
1 13 24 26 2 15 27 38 §6 Mergesort 1. Merge two sorted lists Lpos Lpos Rpos Rpos 1 2 Tpos Tpos Tpos T( N ) = O ( ) where N is the total number of elements. N 3/21
§6 Mergesort 2. Mergesort void MSort( ElementType A[ ], ElementType TmpArray[ ], int Left, int Right ) { int Center; if ( Left < Right ) { /* if there are elements to be sorted */ Center = ( Left + Right ) / 2; MSort( A, TmpArray, Left, Center ); /* T( N / 2 ) */ MSort( A, TmpArray, Center + 1, Right ); /* T( N / 2 ) */ Merge( A, TmpArray, Left, Center + 1, Right ); /* O( N ) */ } } void Mergesort( ElementType A[ ], int N ) { ElementType *TmpArray; /* need O(N) extra space */ TmpArray = malloc( N * sizeof( ElementType ) ); if ( TmpArray != NULL ) { MSort( A, TmpArray, 0, N - 1 ); free( TmpArray ); } else FatalError( "No space for tmp array!!!" ); } If a TmpArray is declared locally for each call of Merge, then S(N) = O( ) N log N 4/21
§6 Mergesort /* Lpos = start of left half, Rpos = start of right half */ void Merge( ElementType A[ ], ElementType TmpArray[ ], int Lpos, int Rpos, int RightEnd ) { int i, LeftEnd, NumElements, TmpPos; LeftEnd = Rpos - 1; TmpPos = Lpos; NumElements = RightEnd - Lpos + 1; while( Lpos <= LeftEnd && Rpos <= RightEnd ) /* main loop */ if ( A[ Lpos ] <= A[ Rpos ] ) TmpArray[ TmpPos++ ] = A[ Lpos++ ]; else TmpArray[ TmpPos++ ] = A[ Rpos++ ]; while( Lpos <= LeftEnd ) /* Copy rest of first half */ TmpArray[ TmpPos++ ] = A[ Lpos++ ]; while( Rpos <= RightEnd ) /* Copy rest of second half */ TmpArray[ TmpPos++ ] = A[ Rpos++ ]; for( i = 0; i < NumElements; i++, RightEnd - - ) /* Copy TmpArray back */ A[ RightEnd ] = TmpArray[ RightEnd ]; } 5/21
§6 Mergesort …… …… A 0 1 2 3 n4 n3 n2 n1 …… …… …… …… …… …… …… …… 3. Analysis Note: Mergesort requires linear extra memory, and copying an array is slow. It is hardly ever used for internal sorting, but is quite useful for external sorting. T( 1) = 1 T( N ) = 2T ( N / 2) + O( N ) Home work: p.229 6.14 Mergesort without recursion = 2kT ( N / 2k) + k * O( N ) = N * T ( 1) + log N * O( N ) = O( N + N log N ) Iterative version : 6/21
13 43 31 57 26 0 81 92 75 65 0 13 26 31 43 57 75 81 92 65 §7 Quicksort -- the fastest known sorting algorithm in practice 1. The Algorithm void Quicksort ( ElementType A[ ], int N ) { if ( N < 2 ) return; pivot = pick any element in A[ ]; Partition S = { A[ ] \ pivot } into two disjoint sets: A1={ aS | a pivot } and A2={ aS | a pivot }; A = Quicksort ( A1, N1) { pivot } Quicksort ( A2, N2); } The best case T(N) = O( ) N log N 13 81 92 43 65 31 57 26 75 0 The pivot is placed at the right place once and for all. 0 13 26 31 43 57 65 75 81 92 7/21
§7 Quicksort 2. Picking the Pivot A Wrong Way: Pivot = A[ 0 ] The worst case: A[ ] is presorted – quicksort will take O( N2 ) time to do nothing A Safe Maneuver: Pivot = random select from A[ ] random number generation is expensive Median-of-Three Partitioning: Pivot = median ( left, center, right ) Eliminates the bad case for sorted input and actually reduces the running time by about 5%. 8/21
§7 Quicksort 8 1 4 9 0 3 5 2 7 6 2 8 5 9 6 9 3. Partitioning Strategy < > > < < > < < < < > i i i i i i j j i j j Not too difficult if we carefully implement it… Uh-oh, there will be many dummy swaps… But hey! At least the sequence will be partitioned into two equal-sized subsequences. No swap… but then T( N ) = … Then T( N ) = O( N2 ). So we’d better stop both i and j and take some extra swaps. What will happen to the sequence: 1, 1, 1, …, 1 ? Good point! How about the other option – that neither i nor j stops? What if there is a key == pivot? How about stop i and j both and then swap? 9/21
§7 Quicksort 4. Small Arrays Problem: Quicksort is slower than insertion sort for small N ( 20 ). Solution: Cutoff when N gets small ( e.g. N = 10 ) and use other efficient algorithms (such as insertion sort). 5. Implementation void Quicksort( ElementType A[ ], int N ) { Qsort( A, 0, N - 1 ); /* A: the array */ /* 0: Left index */ /* N – 1: Right index */ } 10/21
§7 Quicksort /* Return median of Left, Center, and Right */ /* Order these and hide the pivot */ ElementType Median3( ElementType A[ ], int Left, int Right ) { int Center = ( Left + Right ) / 2; if ( A[ Left ] > A[ Center ] ) Swap( &A[ Left ], &A[ Center ] ); if ( A[ Left ] > A[ Right ] ) Swap( &A[ Left ], &A[ Right ] ); if ( A[ Center ] > A[ Right ] ) Swap( &A[ Center ], &A[ Right ] ); /* Invariant: A[ Left ] <= A[ Center ] <= A[ Right ] */ Swap( &A[ Center ], &A[ Right - 1 ] ); /* Hide pivot */ /* only need to sort A[ Left + 1 ] … A[ Right – 2 ] */ return A[ Right - 1 ]; /* Return pivot */ } 11/21
§7 Quicksort void Qsort( ElementType A[ ], int Left, int Right ) { int i, j; ElementType Pivot; if ( Left + Cutoff <= Right ) { /* if the sequence is not too short */ Pivot = Median3( A, Left, Right ); /* select pivot */ i = Left; j = Right – 1; /* why not set Left+1 and Right-2? */ for( ; ; ) { while ( A[ + +i ] < Pivot ) { } /* scan from left */ while ( A[ – –j ] > Pivot ) { } /* scan from right */ if ( i < j ) Swap( &A[ i ], &A[ j ] ); /* adjust partition */ else break; /* partition done */ } Swap( &A[ i ], &A[ Right - 1 ] ); /* restore pivot */ Qsort( A, Left, i - 1 ); /* recursively sort left part */ Qsort( A, i + 1, Right ); /* recursively sort right part */ } /* end if - the sequence is long */ else/* do an insertion sort on the short subarray */ InsertionSort( A + Left, Right - Left + 1 ); } 12/21
§7 Quicksort Assume the average value of T( i ) for any i is 6. Analysis T( N ) = T( i ) + T( N – i – 1 ) + c N Home work: p.230 6.20 More analysis on Quicksort The Worst Case: T( N ) = T( N – 1 ) + c N T( N ) = O( N2 ) The Best Case: [ ... ... ] [ ... ... ] T( N ) = 2T( N / 2 ) + c N Read Figure 6.16 on p.214 for the 5th algorithm on solving this problem. T( N ) = O( N log N ) The Average Case: T( N ) = O( N log N ) 〖Example〗Given a list of N elements and an integer k. Find the kth largest element. 13/21
§7 Quicksort Laboratory Project 4 Quicksort Due: Thursday, November 30th, 2006 at 10:00pm Detailed requirements can be downloaded from http://10.71.45.99/list.asp?boardid=47 Courseware Download Don’t forget to sign you names and duties at the end of your report. 14/21
list list [0] [0] [1] [1] [2] [2] [3] [3] [4] [4] [5] [5] key key d d b b f f c c a a e e table table 4 0 1 1 3 2 0 3 5 4 5 2 table 4 1 3 0 5 2 §8 Sorting Large Structures Problem: Swapping large structures can be very much expensive. Solution: Add a pointer field to the structure and swap pointers instead – indirect sorting. Physically rearrange the structures at last if it is really necessary. 〖Example〗Table Sort The sorted list is list [ table[0] ], list [ table[1] ], ……, list [ table[n1] ] Note: Every permutation is made up of disjoint cycles. temp = d current = 0 3 4 2 5 a c d e f next = 4 2 5 3 0 2 3 4 5 In the worst case there are ? cycles and requires ? record moves. N / 2 3N / 2 T = O( m N ) where m is the size of a structure. 15/21
Proof: K0 K1 T F K1 K2 K0 K2 T T F F stop [0,1,2] stop [1,0,2] K1 K2 K0 K2 T T F F stop [1,2,0] stop [0,2,1] stop [2,0,1] stop [2,1,0] Decision tree for insertion sort on R0, R1, and R2 §9 A General Lower Bound for Sorting 【Theorem】Any algorithm that sorts by comparisons only must have a worst case computing time of ( N log N ). When sorting N distinct elements, there are N! different possible results. Thus any decision tree must have at least N! leaves. If the height of the tree isk, thenN! 2k1(# of leaves in a complete binary tree) k log(N!) + 1 SinceN! (N/2)N/2and log2N! (N/2)log2(N/2) = ( N log2N ) Therefore T(N) = k c N log2N . 16/21
0 1 88 100 count §10 Bucket Sort and Radix Sort Bucket Sort 〖Example〗 Suppose that we have N students, each has a grade record in the range 0 to 100 (thus there are M= 101 possible distinct grades). How to sort them according to their grades in linear time? Algorithm { initialize count[ ]; while (read in a student’s record) insert to list count[stdnt.grade]; for (i=0; i<M; i++) { if (count[i]) output list count[i]; } } What if M >> N ? T(N, M) = O( M+N ) 17/21
§10 Bucket Sort and Radix Sort Bucket 0 1 2 3 4 5 6 7 8 9 Pass 1 0 1 512 343 64 125 216 27 8 729 Pass 2 Pass 3 〖Example〗 Given N = 10 integers in the range 0 to 999 ( M= 1000 ) Is it possible to sort them in linear time? What if we sort according to the Most Significant Digit first? Radix Sort Input: 64, 8, 216, 512, 27, 729, 0, 1, 343, 125 Sort according to the Least Significant Digit first. T=O(P(N+B)) where P is the number of passes, N is the number of elements to sort, and B is the number of buckets. 0 512 125 343 64 1 216 27 8 729 0 125 216 343 512 729 1 8 27 64 Output: 0, 1, 8, 27, 64, 125, 216, 343, 512, 729 18/21
§10 Bucket Sort and Radix Sort A list of records R0, ..., Rn1 is lexically sorted with respect to the keys K 0, K 1, ..., K r1 iff That is, Ki 0 = Ki+10, ... , Ki l = Ki+1l, Ki l+1 < Ki+1l+1 for some l < r 1. K 0 [Suit] < < < K 1 [Face value] Sorting result : 2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A 2 ... A 2 ... A 2 ... A 2 ... A Suppose that the record Ri has r keys. Ki j ::= the j-th key of record Ri Ki 0 ::= the most significant key of record Ri Ki r1 ::= the least significant key of record Ri 〖Example〗 A deck of cards sorted on 2 keys 19/21
§10 Bucket Sort and Radix Sort 5 4 A 3 5 4 A 3 MSD ( Most Significant Digit ) Sort Sort on K0: for example, create 4 buckets for the suits Sort each bucket independently (using any sorting technique) 20/21
§10 Bucket Sort and Radix Sort 2 2 ... 4 5 3 3 2 2 4 5 3 3 A A A A LSD ( Least Significant Digit ) Sort Sort on K1: for example, create 13 buckets for the face values Home work: p.231 6.32 An application of Bucket Sort [ Think: why is it faster than O(N log N)? ] Reform them into a single pile Create 4 buckets and resort Question: Is LSD always faster than MSD? 21/21