1.快速排序
不稳定
分而治之
找主元pivot,小于主元划分为一个子集,大于主元的划分为一个子集
然后进行递归
最好情况:每次主元正好中分,T(N) = O( NlogN )
选主元 的方法有很多,这里用 取头、中、尾的中位数。
直接选A[0]为pivot,时间复杂度T ( N ) = O( N ) + T ( N–1 ) = O( N ) + O ( N–1 ) + T( N–2 ) = = O( N ) + O ( N–1 ) + …+ O( 1 ) = O( N^2 )
随机取pivot:rand()函数 也很费
取头、中、尾的中位数……
子集划分
i指向8,j指向7.
8>6,i不动,7>6,j--;j指向2,2<6,j不动 交换8和2;
i++,i指向1,1<6,i++;i指向4,4<6,i++;i指向9,9>6,i不动;
j--,j指向5,5<6,j不动,交换5和9;
i++,i指向0,0<6,i++;i指向3,3<6,i++;i指向9,9>6,i不动;
j--,j指向3,3<6,j不动.
i>j,结束,6放到i位置,即6和9交换
如果有元素正好等于pivot怎么办:
停下来交换:会产生很多不必要的交换。(一串相等的序列)
不理它,继续移动指针:pivot位置靠近一段,最糟糕会在最右边端,和pivot取A[0]一样,O( N^2 )
综合考虑,选第一种,停下来交换。
小规模数据的处理
快速排序的问题
用递归……
对小规模的数据(例如N不到100)可能还不如插入排序快
解决方案
当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)
在程序中定义一个Cutoff的阈值
1 #include <stdio.h> 2 typedef int ElementType; 3 4 void Swap( ElementType *a, ElementType *b ) 5 { 6 ElementType t = *a; 7 *a = *b; 8 *b = t; 9 } 10 11 void InsertionSort(ElementType A[], int N) 12 { 13 int i; 14 for (int P = 1; P < N; P++ ) { 15 ElementType temp = A[P]; //取出未排序序列中第一个元素 16 for (i = P; i > 0 && A[i-1] > temp; i-- ) 17 A[i] = A[i-1]; //依次与已排序序列中元素比较并右移 18 A[i] = temp; 19 } 20 } 21 22 /* 快速排序 */ 23 ElementType Median3( ElementType A[], int Left, int Right ) 24 { 25 int Center = (Left+Right) / 2; 26 if ( A[Left] > A[Center] ) 27 Swap( &A[Left], &A[Center] ); 28 if ( A[Left] > A[Right] ) 29 Swap( &A[Left], &A[Right] ); 30 if ( A[Center] > A[Right] ) 31 Swap( &A[Center], &A[Right] ); 32 /* 此时A[Left] <= A[Center] <= A[Right] */ 33 Swap( &A[Center], &A[Right-1] ); /* 将基准Pivot藏到右边*/ 34 /* 只需要考虑A[Left+1] … A[Right-2] */ 35 return A[Right-1]; /* 返回基准Pivot */ 36 } 37 38 void Qsort( ElementType A[], int Left, int Right ) 39 { /* 核心递归函数 */ 40 int Pivot, Cutoff = 50, Low, High;//阈值的定义 41 42 if ( Cutoff <= Right-Left ) { /* 如果序列元素充分多,进入快排 */ 43 Pivot = Median3( A, Left, Right ); /* 选基准 */ 44 Low = Left; High = Right-1; 45 while (1) { /*将序列中比基准小的移到基准左边,大的移到右边*/ 46 while ( A[++Low] < Pivot ) ; 47 while ( A[--High] > Pivot ) ; 48 if ( Low < High ) Swap( &A[Low], &A[High] ); 49 else break; 50 } 51 Swap( &A[Low], &A[Right-1] ); /* 将基准换到正确的位置 */ 52 Qsort( A, Left, Low-1 ); /* 递归解决左边 */ 53 Qsort( A, Low+1, Right ); /* 递归解决右边 */ 54 } 55 else InsertionSort( A+Left, Right-Left+1 ); /* 元素太少,用简单排序 */ 56 } 57 58 void QuickSort( ElementType A[], int N ) 59 { /* 统一接口 */ 60 Qsort( A, 0, N-1 ); 61 } 62 63 int main() 64 { 65 int a[] = {34,8,64,51,32,21}; 66 QuickSort(a, 6); 67 for(int i = 0; i < 6; i++) 68 printf("%d ",a[i]); 69 return 0; 70 } 71 72 QuickSort