快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序算法是基于分治策略的另一种排序算法。其基本思想是,对于输入的子数组a[p,r],按以下三个步骤进行排序。
(1) 分解(Divide) 以a[p] 为基准元素将a[p:r]划分为3段a[p:q-1],a[q],和a[q+1:r]。使a[p:q-1]中的任一元素小于a[q],而a[q+1:r]中的任一元素大于a[q]。下标q在划分中确定。
(2) 递归求解(Conquer):通过递归调用快速算法分别对a[p,q-1]和a[q+1,r]进行排序。
(3) 不需要再进行合并排序,当递归调用排序后,a[p:r]就已排好序。

时间复杂性分析

最坏情形:
image.png解此递归方程可得T(n)=O(n2)。
最好情形:
image.png解此递归方程可得T(n)=O(nlogn)。

  1. template<class Type>
  2. void QuickSort(Type a[], int p, int r)
  3. {
  4. if (p<r)
  5. {
  6. int q=Partition(a,p,r);
  7. QuickSort (a,p,q-1); //对左半段排序
  8. QuickSort (a,q+1,r); //对右半段排序
  9. }
  10. }
  1. #include<iostream>
  2. using namespace std;
  3. #define N 10
  4. template<class Type>
  5. int Partition(Type a[], int p, int r) {
  6. int i = p, j = r + 1;
  7. Type x = a[p];//存放待排数组左边数字
  8. while (true){
  9. while (a[++i] < x && i < r);//前往后找到大于x的数
  10. while (a[--j] > x);//后往前找到小于x的数
  11. if (i >= j)
  12. break;
  13. swap(a[i], a[j]);
  14. }
  15. a[p] = a[j];
  16. cout <<j<<" "<< a[j] << endl;
  17. a[j] = x;
  18. return j;//此时j的左边比a[j]小,右边比a[j]大
  19. }
  20. template<class Type>
  21. void QuickSort(Type a[], int p, int r) {
  22. if (p < r){
  23. int q = Partition(a, p, r);//此时q的左边比a[q]小,右边比a[q]大
  24. QuickSort(a, p, q - 1);//递归排序左边
  25. QuickSort(a, q + 1, r);//右边
  26. }
  27. }
  28. template<class Type>
  29. void Print(Type a[]) {
  30. for(int i=0;i<N;i++)
  31. cout << a[i] << " ";
  32. cout << endl;
  33. }
  34. int main() {
  35. int a[N];
  36. for (int i = 0; i <N ; i++)
  37. a[i] = rand() % N + 1;
  38. int i = N;
  39. Print(a);
  40. QuickSort(a, 0, N-1);//升序
  41. Print(a);
  42. return 0;
  43. }

一些改进方法:
快速排序算法的性能取决于划分的对称性,通过修改函数Partition,,可以设计出采用随机选择策略的快速排序算法。
快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速 排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可以满足一个人一辈子的人品需求。”
随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直接减弱。对于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。解决方法是用一种方法进行扫描,使没有交换的情况下主元保留在原位置。

  1. #include<iostream>
  2. using namespace std;
  3. #define N 20
  4. template<class Type>
  5. void Print(Type a[]) {
  6. for(int i=0;i<N;i++)
  7. cout << a[i] << " ";
  8. cout << endl;
  9. }
  10. template<class Type>
  11. int Partition(Type a[], int p, int r) {
  12. int i = p, j = r + 1;
  13. Type x = a[p];//存放待排数组左边数字
  14. while (true){
  15. while (a[++i] < x && i < r);//前往后找到大于x的数
  16. while (a[--j] > x);//后往前找到小于x的数
  17. if (i >= j)
  18. break;
  19. swap(a[i], a[j]);
  20. }
  21. a[p] = a[j];
  22. //cout <<j<<" "<< a[j] << endl;
  23. a[j] = x;
  24. return j;//此时j的左边比a[j]小,右边比a[j]大
  25. }
  26. template<class Type>
  27. void QuickSort(Type a[], int p, int r) {
  28. if (p < r){
  29. int q = Partition(a, p, r);//此时q的左边比a[q]小,右边比a[q]大
  30. printf("%d\t%d\t",q,a[q]);
  31. //cout<<q<<" " <<a[q]<<" ";
  32. Print(a);
  33. QuickSort(a, p, q - 1);//递归排序左边
  34. QuickSort(a, q + 1, r);//右边
  35. }
  36. }
  37. int main() {
  38. int a[N];
  39. for (int i = 0; i <N ; i++)
  40. a[i] = rand() % N + 1;
  41. //int i = N;
  42. printf("随机生成数:\t");
  43. Print(a);
  44. QuickSort(a, 0, N-1);//升序
  45. printf("排序后:\t\t");
  46. Print(a);
  47. return 0;
  48. }