转自: http://blog.csdn.net/lingfengtengfei/article/details/12376889
快速排序法事应用最广泛的排序算法之一,最佳情况下时间复杂度是 O(nlogn)。但是最坏情况下可能达到O(n^2)。说明快速排序达到最坏情况的原因。并提出改善方案并实现之。
答:
改进方案:改进选取枢轴的方法
1、选取随机数作为枢轴。
但是随机数的生成本身是一种代价,根本减少不了算法其余部分的平均运行时间。
2、使用左端,右端和中心的中值做为枢轴元。
经验得知,选取左端,右端,中心元素的中值会减少了快排大约 14%的比较。
3、每次选取数据集中的中位数做枢轴。
选取中位数的可以在 O(n)时间内完成。(证明见《算法导论(第二版) 》) P111 第九章中位数
和顺序统计学:在平均情况下,任何顺序统计量(特别是中位数)都可以在线性时间内得到。
快排的分割策略:
第一步是通过将枢轴元与最后一个元素交换使得枢轴元离开要被分割的数据段;i 从第一个
元素开始而 j 从倒数第二个元素开始。当 i 在 j 左边时,我们将 i 右移,移过那些小于枢轴
元的元素,并将 j 左移,移过那些大于枢轴元的元素。当 i 和 j 停止时,i 指向的是大元素,
j指向的是小元素。如果 i 在 j 左边,那么将这两个元素互换。 如果此时 i 和 j 已经交错即 i>j
所以不交换。此时把枢轴元与 i 所指的元素交换。
实例演示:
其他可以改进的地方(网络搜集) :
1、 快速排序在处理小规模数据时的表现不好.
这个时候可以改用插入排序。
当数据规模小于一定程度时,改用插入排序。具体小到何种规模时,采用插入排序,这个理
论上还不解,一些文章中说是 5 到 25 之间。SGI STL 中的快速排序采用的值是 10.
2、对于一个每个元素都完全相同的一个序列来讲,快速排序也会退化到 O(n^2)。
要将这种情况避免到,可以这样做:
在分区的时候,将序列分为 3 堆,一堆小于中轴元素,一堆等于中轴元素,一堆大于中轴元
素,下次递归调用快速排序的时候,只需对小于和大于中轴元素的两堆数据进行排序,中间
等于中轴元素的一堆已经放好
#include<stdio.h>
#include<stdlib.h>
//选取枢轴,将所有元素小于它的移到它的左边,大于它的移到它的右边,返回它的位置.
int partition(int A[],int low,inthigh)
{
if(A == NULL || low< 0 || high < 0 || low > high) //m>f>l
{
throw std::exception("invalidParameters!");
}
//选取枢轴位置,取首元素,中间元素和末尾元素的中值作为枢轴
int mid = low+(high -low) >> 1;
int firstElem = A[low];
int lastElem = A[high];
int midElem =A[mid];
int index = GetMiddleValue(A,low,high);//中位数的位置
//将枢轴元素放在第一个位置
if(index != low)//交换
{
int temp =A[index];
A[index]= firstElem;
A[low]= temp;
}
//定义两个标记,一个负责向后扫描,一个负责向前扫描
//向后每遇到一个比它大的就交换,向前扫描每遇到一个比它小的就交换
int x = A[low];//枢轴元素
int flagL =low;
int flagH =high;
while(flagL <flagH)
{
while(A[flagH] >= x &&flagL < flagH)//找到第一个比枢轴小的元素,放到当前flagL的位置
flagH--;
if(flagL < flagH)
A[flagL++] =A[flagH];
else
break;
while(A[flagL] <= x &&flagL < flagH)//找到第一个比枢轴大的元素,放到当前flagH的位置
flagL++;
if(flagL <flagH)
A[flagH--] =A[flagL];
else
break;
}
A[flagL]= x;
return flagL;
}
void qsort(int A[],intlow,int high)
{
if(low <high)
{
int k =partition(A,low,high);
qsort(A,low,k-1);
qsort(A,k+1,high);
}
}
int main()
{
int A[] ={0, 10, -5, 7, 8, -18, 33};
qsort(A,0,sizeof(A)/sizeof(int)-1);
for(int i=0;i<sizeof(A)/sizeof(int);i++)
printf("%d ",A[i]);
return 0;
}
//3值取中值
intGetMiddleValue(int A[],int low,int high)
{
int mid=low+(high-low)>>1;
int y1=A[low]>A[mid]?low:mid;
int y2=A[low]>A[high]?low:high;
int y3=A[mid]>A[high]?mid:high;
if (y1==y2)
{
return y3;
}
else
return A[y1]>A[y2]?y2:y1;
}
或
a + b + c - (a > b ? a > c ? a : c : b > c ? b : c) - (a < b ? a < c ? a : c : b < c ? b : c)