转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/30729523
高速排序是由东尼.霍尔所发展的一种排序算法。在平均状况下,排序n 个项目要O(n log n)次比較。在最坏状况下则须要Ο(n2)次比較,但这样的状况并不常见。
其实,高速排序通常明显比其它Ο(n log n) 算法更快,由于它的内部循环(inner loop)能够在大部分的架构上非常有效率地被实现出来。
一.排序步骤总结:
高速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
1.用三数中值切割法找出枢纽元(基准)。
2.又一次排序数列,全部元素比基准值小的摆放在基准前面,全部元素比基准值大的摆在基准的后面(同样的数能够到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
二.高速排序算法
/*************************************************************** *版权全部 (C)2014,公司名称。 * *文件名:高速排序法 *内容摘要:无 *其他说明:无 *当前版本号:V1.0 *作 者:若云流风 *完毕日期:2014.6.14 ***************************************************************/ #include <stdio.h> #define N (14) #define cutoff (3) //截止范围小于等于3 void disp(void); int a[N]={8,14,3,12,10,7,5,1,9,4,11,13,2,6}; /*交换函数*/ void Swap(int *a, int *b) { int t; t = *a; *a = *b; *b = t; } /*三种值切割*/ int Median3(int a[], int left, int right) { //取数据的头、尾和中间三个数。并对他们进行排序 //排序结果直接保存在数组中 int centre = (left + right)/2; if(a[left] > a[centre]) Swap(&a[left], &a[centre]); if(a[left] > a[right]) Swap(&a[left], &a[right]); if(a[centre] > a[right]) Swap(&a[centre], &a[right]); //把中值,即枢纽与数组倒数第二个元素交换 Swap(&a[centre], &a[right - 1]); return a[right - 1];//返回枢纽 } /*高速排序程序*/ void QSort(int a[], int left, int right) { //假设须要排序的数据大于3个则使用高速排序 if(right - left >= cutoff) { //取得枢纽的值 int centre = Median3(a, left, right); int i = left; int j = right - 1; while(1) { /*向后扫描数组,找出大于枢纽元素的元素 * 因为在选择枢纽时。已经把比枢纽值大的数据放在right位置 * 所以不会越界 */ while(a[++i] < centre); //当i大于等于中枢元素时候跳出循环 /*向前扫描数组,找出小于枢纽元素的元素 * 因为在选择枢纽时,已经把比枢纽值小的数据放在left位置 * 所以不会越界 */ while(a[--j] > centre); //把比枢纽小的数据放在前部,大的放到后部 if(i < j) { Swap(&a[i], &a[j]); printf(" 高速排序结果: "); disp(); //打印 } else { //disp(); break; } } Swap(&a[i], &a[right - 1]); //还原枢纽元素 printf(" 还原枢纽元素后结果: "); disp(); QSort(a, left, i - 1); QSort(a, i + 1, right); } else //假设要排序的数据非常少。少于等于3个,则直接使用冒泡排序 { InsertionSort(a+left, right - left + 1); } } /*插入排序*/ int InsertionSort(int a[],int M) { int j,p,temp; for(p=1;p<M;p++) { temp=a[p]; //a[p]和左面的有序数列去比較 /*j>0保证不溢出,因为当j=0时啊a[j-1]非法。用a[p]分别与左面的值相比較 **假设a[p]小的话则互换位置, */ for(j=p; j>0 && a[j-1]>temp;j--) { a[j]=a[j-1]; } a[j]=temp; } printf(" 插入排序结果: "); disp(); } /*输出函数*/ void disp(void) { int i; printf(" 排序结果: "); for(i=0;i<N;i++) { printf("%d", a[i]); printf(" "); } } int main(void) { QSort(a , 0, N-1); // disp(); return 0; }
三.算法会说话
1.输出结果
2.整体过程分析
a.三数中值切割法
8,14,3,12,10,7,5,1,9,4,11,13,2,6
红色的三个数字依照大小顺序排好。中间的那个元素叫做中枢元,将中枢元和倒数第二个元素互换位置后返回。
5,14,3,12,10,7,2,1,9,4,11,13,6,8
b.高速排序
5,14,3,12,10,7,2,1,9,4,11,13,6,8
(找出比中枢元大的) i --> <--j(找出比中枢元小的)
5,14,3,12,10,7,2,1,9,4,11,13,6,8
i <--交换--> j
i <--交换--> j
i <--> j
j i i>j退出
还原枢纽元素
注意此时产生的结果就是以枢纽元素为分界线,左面的所有小于枢纽元素,右面的所有大于枢纽元素
先对6前面的排序:
5, 4, 3, 1, 2
2, 4, 1, 3, 5
i j
2,1(插入排序) 3 4 ,5(插入排序)
6后面的排序和前面类似。故不再详细分析。
參考:1.维基百科
2.数据结构与算法分析---C语言描写叙述 Mark Allen Weiss 著