20230407 10.1. 快速排序
快速排序
什么是快速排序算法的最好情况?每次正好中分 T(N) = O( NlogN )
void Quicksort( ElementType A[], int N )
{
if ( N < 2 ) return;
pivot = 从A[]中选一个主元;
将S = { A[] \ pivot } 分成2个独立子集:
A1={ a∈S | a <= pivot } 和
A2={ a∈S | a >= pivot };
A[] = Quicksort(A1,N1) ∪
{pivot} ∪
Quicksort(A2,N2);
}
- 主元的选择至关重要,有多种取法
- 取头、中、尾的中位数
- 例如 8、12、3的中位数就是8
- 取头、中、尾的中位数
快速排序的问题
- 用递归……
- 对小规模的数据(例如N不到100)可能还不如插入排序快
解决方案 - 当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)
- 在程序中定义一个Cutoff的阈值
算法实现
void Quick_Sort(ElementType A[],int N)
{
Quicksort( A, 0, N-1 );
}
void Quicksort( ElementType A[], int Left, int Right )
{
if ( Cutoff <= Right-Left ) {
Pivot = Median3( A, Left, Right );
i = Left; j = Right – 1;
for( ; ; ) {
while ( A[ ++i ] < Pivot ) { }
while ( A[ ––j ] > Pivot ) { }
if ( i < j )
Swap( &A[i], &A[j] );
else break;
}
Swap( &A[i], &A[ Right-1 ] );
Quicksort( A, Left, i-1 );
Quicksort( A, i+1, Right );
}
else
Insertion_Sort( A+Left, Right-Left+1 );
}
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 ] );
/* A[ Left ] <= A[ Center ] <= A[ Right ] */
Swap( &A[ Center ], &A[ Right-1 ] ); /* 将pivot藏到右边 */
/* 只需要考虑 A[ Left+1 ] … A[ Right–2 ] */
return A[ Right-1 ]; /* 返回 pivot */
}