本文仅用作学习记录,大神勿喷O(∩_∩)O~
代码一、百度百科C++语言版本代码,参考数据结构p274(清华大学出版社,严蔚敏)
1 void Qsort1(int a[], int low, int high)//百度百科C++语言版本代码 2 {/*参考数据结构p274(清华大学出版社,严蔚敏)*/ 3 if(low >= high) return; 4 int first = low; 5 int last = high; 6 int key = a[first];/*用字表的第一个记录作为枢轴*/ 7 8 while(first < last) 9 { 10 while(first < last && a[last] >= key) 11 { 12 --last; 13 } 14 a[first] = a[last];/*将比第一个小的移到低端*/ 15 while(first < last && a[first] <= key) 16 { 17 ++first; 18 } 19 a[last] = a[first]; 20 /*将比第一个大的移到高端*/ 21 } 22 a[first] = key;/*枢轴记录到位*/ 23 Qsort1(a, low, first-1); 24 Qsort1(a, first+1, high); 25 }
代码二、百度百科C语言版本代码
1 void Qsort2(int *a, int left, int right)//百度百科C语言版本代码 2 { 3 if(left >= right)/*如果左边索引大于或者等于右边的索引就代表已经整理完成一个组了*/ 4 { 5 return ; 6 } 7 int i = left; 8 int j = right; 9 int key = a[left]; 10 11 while(i < j) /*控制在当组内寻找一遍*/ 12 { 13 while(i < j && key <= a[j])/*而寻找结束的条件就是,1,找到一个小于或者大于key的数(大于或小于取决于你想升序还是降序)2,没有符合条件1的,并且i与j的大小没有反转*/ 14 { 15 j--;/*向前寻找*/ 16 } 17 a[i] = a[j];/*找到一个这样的数后就把它赋给前面的被拿走的i的值(如果第一次循环且key是a[left],那么就是给key)*/ 18 19 while(i < j && key >= a[i])/*这是i在当组内向前寻找,同上,不过注意与key的大小关系停止循环和上面相反,因为排序思想是把数往两边扔,所以左右两边的数大小与key的关系相反*/ 20 { 21 i++; 22 } 23 a[j] = a[i]; 24 } 25 26 a[i] = key;/*当在当组内找完一遍以后就把中间数key回归*/ 27 Qsort2(a, left, i - 1);/*最后用同样的方式对分出来的左边的小组进行同上的做法*/ 28 Qsort2(a, i + 1, right);/*用同样的方式对分出来的右边的小组进行同上的做法*/ 29 /*当然最后可能会出现很多分左右,直到每一组的i = j 为止*/ 30 }
代码三、坐在马桶上看算法:快速排序。 链接:http://developer.51cto.com/art/201403/430986.htm
(来源页面评论代码有误,测试没发现问题。)
1 void Qsort3(int a[],int left,int right) //坐在马桶上看算法:快速排序。http://developer.51cto.com/art/201403/430986.htm 2 { 3 int i,j,t,temp; 4 if(left>right) return; 5 6 temp=a[left]; //temp中存的就是基准数 7 i=left; 8 j=right; 9 while(i!=j) 10 { 11 //顺序很重要,要先从右边开始找 12 while(i<j && a[j]>=temp) 13 j--; 14 //再找右边的 15 while(i<j && a[i]<=temp) 16 i++; 17 //交换两个数在数组中的位置 18 if(i<j) 19 { 20 t=a[i]; a[i]=a[j]; a[j]=t; 21 } 22 } 23 //最终将基准数归位 24 a[left]=a[i]; 25 a[i]=temp; 26 27 Qsort3(a,left,i-1);//继续处理左边的,这里是一个递归的过程 28 Qsort3(a,i+1,right);//继续处理右边的 ,这里是一个递归的过程 29 }
代码四、白话经典算法系列之六 快速排序 链接: http://blog.csdn.net/morewindows/article/details/6684558#
链接页面评论一致认为作者讲解非常棒。
1 void Qsort4(int s[], int l, int r)//白话经典算法系列之六 快速排序 http://blog.csdn.net/morewindows/article/details/6684558# 2 { 3 if (l < r) 4 { 5 int i = l, j = r, x = s[l]; 6 while (i < j) 7 { 8 while(i < j && s[j] >= x) // 从右向左找第一个小于x的数 9 j--; 10 if(i < j) 11 s[i++] = s[j]; 12 13 while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数 14 i++; 15 if(i < j) 16 s[j--] = s[i]; 17 } 18 s[i] = x; 19 Qsort4(s, l, i - 1); // 递归调用 20 Qsort4(s, i + 1, r); 21 } 22 }
代码五、博客园~大器晚成~的代码 链接:http://www.cnblogs.com/luchen927/archive/2012/02/29/2368070.html
原文代码有误,评论里面已经有园友指出。这里摘抄时已经修改,否则当待排序列有相等值则可能会死循环 。
1 void Qsort5(int *v, int left, int right)//博客园“大器晚成”的代码http://www.cnblogs.com/luchen927/archive/2012/02/29/2368070.html 2 {//原文代码有错误,已经修改,否则当待排序列有相等值则会死循环 。修改以后,本代码与百度百科代码是相同 3 if(left < right) 4 { 5 int key = v[left]; 6 int low = left; 7 int high = right; 8 while(low < high) 9 { 10 while(low < high && v[high] >= key)//原文 while(low < high && v[high] > key) 11 { 12 high--; 13 } 14 v[low] = v[high]; 15 while(low < high && v[low] <= key)//原文while(low < high && v[low] < key) 16 { 17 low++; 18 } 19 v[high] = v[low]; 20 } 21 v[low] = key; 22 Qsort5(v,left,low-1); 23 Qsort5(v,low+1,right); 24 } 25 }
代码六、《C++一本通》page191快速排序代码(请阅读这一段代码)
1 void Qsort6(int *a,int l,int r)//《C++一本通》page191快速排序代码 2 { 3 int i,j,mid,p; 4 i=l; 5 j=r; 6 mid=a[(l+r) / 2]; //将当前序列在中间位置的数定义为分隔数 7 do 8 { 9 while (a[i]<mid) i++;//在左半部分寻找比中间数大的数 10 while (a[j]>mid) j--;//在右半部分寻找比中间数小的数 11 if (i<=j) 12 { //若找到一组与排序目标不一致的数对则交换它们 13 p=a[i];a[i]=a[j];a[j]=p; 14 i++;j--; //继续找 15 } 16 }while(i<=j);//注意这里不能少等号 17 if (l<j) Qsort6(a,l,j);//若未到两个数的边界,则递归搜索左右区间 18 if (i<r) Qsort6(a,i,r); 19 }
代码七、来自北大郭炜老师在网易云课堂开设的算法课程
1 #include <iostream> 2 using namespace std; 3 void swap(int & a,int & b) //交换变量a,b值 4 { 5 int tmp = a; 6 a = b; 7 b = tmp; 8 } 9 void QuickSort(int a[],int s,int e) 10 { 11 if( s >= e) return; 12 int k = a[s]; 13 int i = s,j = e; 14 while( i != j ) 15 { 16 while( j > i && a[j] >= k ) --j; 17 swap(a[i],a[j]); 18 while( i < j && a[i] <= k ) ++i; 19 swap(a[i],a[j]); 20 } //处理完后, a[i] = k 21 QuickSort(a,s,i-1); 22 QuickSort(a,i+1,e); 23 } 24 int a[] = { 93,27,30,2,8,12,2,8,30,89}; 25 int main() 26 { 27 int size = sizeof(a)/sizeof(int); 28 QuickSort(a,0,size-1); 29 for(int i = 0;i < size; ++i) 30 cout << a[i] << ","; 31 cout << endl; 32 return 0; 33 }
注意:在快排过程中划分区间时,必须要有等号,比如:
1 int i=left,j=right,key=a[left]; 2 while(i<j) 3 { 4 while(i<j&&key>=a[j]) j--;//必须取等号,否则当数组两头的数相等时会死循环 5 a[i]=a[j]; 6 while(i<j&&key<=a[i]) i++;//必须取等号,否则当数组两头的数相等时会死循环 7 a[j]=a[i]; 8 }
这种地方>=不能改为>,否则可能死循环。
测试用的主函数
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<time.h> 4 5 int cmp(const void *a,const void *b) 6 { return *(int*)a - *(int*)b; } 7 int main() 8 { 9 int a[50],b[50],c[50],d[50],e[50],f[50],g[50],h[50]; 10 int n,i,k=100000,index=1,count=0; 11 srand((unsigned)time(0)); 12 13 freopen("res.out","w",stdout); 14 for(;k>0;k--) 15 { 16 n=(rand()%2==1?49:50); 17 for(i=0;i<n;i++) 18 { 19 a[i]=rand()%3000; 20 h[i]=g[i]=f[i]=e[i]=d[i]=c[i]=b[i]=a[i]; 21 } 22 23 Qsort1(a, 0, n - 1); 24 Qsort2(b, 0, n - 1); 25 qsort(c,n,sizeof(c[0]),cmp); 26 Qsort3(e,0,n-1); 27 Qsort4(f,0,n-1); 28 Qsort5(g,0,n-1); 29 Qsort6(h,0,n-1); 30 31 for(i= 0; i < n; i++) 32 { 33 if(a[i]!=c[i]||b[i]!=c[i]||e[i]!=c[i]||f[i]!=c[i]||g[i]!=c[i]||h[i]!=c[i]) 34 break; 35 } 36 if(i<n) 37 { 38 printf("case %d:\n",index); 39 printf("A:");//Qsort1的结果 40 for(i=0;i<n;i++) 41 printf("%d ",a[i]); 42 printf("\n"); 43 44 printf("B:");//Qsort2的结果 45 for(i=0;i<n;i++) 46 printf("%d ",b[i]); 47 printf("\n"); 48 49 printf("C:");//标准结果序列 50 for(i=0;i<n;i++) 51 printf("%d ",c[i]); 52 printf("\n"); 53 54 printf("E:");//Qsort3的结果 55 for(i=0;i<n;i++) 56 printf("%d ",e[i]); 57 printf("\n"); 58 59 printf("F:");//Qsort4的结果 60 for(i=0;i<n;i++) 61 printf("%d ",f[i]); 62 printf("\n"); 63 64 printf("G:");//Qsort5的结果 65 for(i=0;i<n;i++) 66 printf("%d ",g[i]); 67 printf("\n"); 68 69 printf("H:");//Qsort6的结果 70 for(i=0;i<n;i++) 71 printf("%d ",h[i]); 72 printf("\n"); 73 74 printf("D:");//原未排序序列 75 for(i=0;i<n;i++) 76 printf("%d ",d[i]); 77 printf("\n"); 78 } 79 else { printf("case %d is ok!\n",index); count++;} 80 index++; 81 } 82 printf("%d of %d is ok!\n",count,index-1); 83 return 0; 84 }
其实 Qsort1、Qsort2、Qsort5(博客园代码修改以后)三份代码是一样的
Qsort4跟上面几个是差不多的,但稍有一点点改变
Qsort3思路变化比较大一些。
Qsort6简直就是另类代码风格,瞎搞的,不过也是对的。
学习记住 Qsort1、Qsort2、Qsort5之一或者Qsort4即可。
经过在洛谷OJ P1177 测试,代码六应该是最合理的,大家还是记住代码六吧。。。。。。
(利用库函数qsort在洛谷OJ P1177提交确实也是AC的,然后利用代码六去提交也可以过。说明OJ的数据没问题。)
其余代码的分割点元素的选择都是选第一个元素,这个决策是一个不合理的决策,会导致算法的时间复杂度在某些情况下变为N^2级别的。虽然代码六不能够完全避免这个情况,但是相对而言比较合理一些。具体论述请参考《数据结构与算法分析:C语言描述(原书第2版)》对快速排序的描述。