快速排序
基本思想: 首先对无序的记录序列进行“一次划分”,之后分别对分割所得两个子序列“递归”进行快速排序。
QuickSort ( List ) {
if ( List的长度大于1) {
将序列List划分为两个子序列
LeftList 和 Right List;
QuickSort ( LeftList );
QuickSort ( RightList );
将两个子序列 LeftList 和 RightList
合并为一个序列List;
}
}
(1) 将 R[j]和 枢轴 进行比较,if R[j].key ≥ 枢轴 j--
else swap( ) , i++
(2) 将 R[i]和 枢轴 进行比较,if R[i].key ≤ 枢轴 i++
else swap( ), j--
21,25,49,16,25,06
过程如下:
06,25,49,16,25,21
06,21,49,16,25,25
06,16,49,21,25,25
06,16,21,49,25,25
一趟下来为:
06,16,21,49,25,25
06<21则互换位置,此时的06换到21的左边了,然后i++,,25>21,则换位置,此时的25在21右边,然后j--,到25,25>21,则不动,j--,此时16<21,则互换位置,16在21的左边,然后i++,到49,49>21则互换位置,49跑到了21的右边,此时j--,这时候i==j,则结束一趟排序。
有什么改进的地方呢?
其实可以用一个temp来记录21这个中心值。
temp=21;
06,25,49,16,25,()
06,(),49,16,25,25
06,(),49,16,25,25
06,16,49,(),25,25
06,16,(),49,25,25
此时i==j,()里面填上21就可以了
则把a[i]=temp。就行了
算法实现:
QuickSort ( List ) {
if ( List的长度大于1) {
将序列List划分为两个子序列
LeftList 和 Right List;
QuickSort ( LeftList );
QuickSort ( RightList );
将两个子序列 LeftList 和 RightList
合并为一个序列List;
}
}
函数头:quicksort(int a[],int left,int right)
初始化:i=left;j=right;int temp=a[left];
划分:do{一次划分} while(i<j);
中心元素填入:a[i]=temp;
递归地对剩余段作快速排序
quicksort(a,left,i-1);
quicksort(a,i+1,right);
left,right用于限定要排序数列的范围,temp即为中心元素
i=left;j=right;int temp=a[left];
do
{ //从右向左找第1个不小于中心元素的位置j
while( a[j] > temp && i<j) j--;
if(i<j)
{ a[ i ] = a[ j ];
i++; }
a[i]=temp;
//从左向右找第1个不大于中心元素的位置i
while(a[i]<temp && i<j ) i++;
if(i<j)
{ a[j]=a[i];
j--; }
}while(i<j);
// a[i]=temp; //将中心元素t填入最终位置
快速排序的趟数取决于递归树的高度。
如果每次划分对一个对象定位后, 该对象的左侧子序列与右侧子序列的长度相同, 则下 一步将是对两个长度减半的子序列进行排序, 这是最理想的情况。
可以证明, 函数quicksort的平均计算时间也是O(nlog2n)。实验结果表明: 就平均计算时间而言, 快速排序是所有内排序方法中最好的一个。
快速排序是递归的,需要有一个栈存放每层递归调用时的指针和参数。
最大递归调用层次数与递归树的高度一致,理想情况为 log2(n+1) 。因此,要求存储开销为 O(log2n)。
在最坏的情况, 即待排序对象序列已经按其排序码从小到大排好序的情况下, 其递归树成为单支树, 每次划分只得到一个比上一次少一个对象的子序列。总的排序码比较次数将达
快速排序是一种不稳定的排序方法。