1.快速排序

不稳定

分而治之

数据结构学习笔记06排序 (快速排序、表排序、基数排序)

 

找主元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()函数 也很费

  取头、中、尾的中位数……

子集划分

数据结构学习笔记06排序 (快速排序、表排序、基数排序)

i指向8,j指向7.

8>6,i不动,7>6,j--;j指向2,2<6,j不动 交换8和2;

数据结构学习笔记06排序 (快速排序、表排序、基数排序)

i++,i指向1,1<6,i++;i指向4,4<6,i++;i指向9,9>6,i不动;

j--,j指向5,5<6,j不动,交换5和9;

数据结构学习笔记06排序 (快速排序、表排序、基数排序)

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交换

数据结构学习笔记06排序 (快速排序、表排序、基数排序)

如果有元素正好等于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
QuickSort

相关文章: