快速排序 递归 与 非递归

素颜马尾好姑娘i 2022-09-18 01:59 296阅读 0赞

递归法

#

快排的思想

设当前需要排序的数组为int A[bt…ed]

分解:
在A[]中任选一个记录作为基准(pivot),以pivot为基准将数组A划分为两个小的数组A[bt…pivot-1]和A[pivot+1…ed],并使左边的数组元素均小于等于pivot,右边数组元素均大于等于piovt。此时,pivot处于正确的位置上,它不需要再参加后续的排序

求解:
递归的调用快速排序,对A[bt…pivot-1]和A[pivot+1…ed]进行快速排序

组合:
跟归并排序不同,因为每次调用快速排序,左右两个数组均已有序,因此对于快速排序来说,组合是一个空操作

实现代码(C语言)

快排用c实现其实可以直接调用系统的qsort函数,自己写compare比较函数即可,在php里是调用usort函数,但是面试考察大部分都是不能调用系统函数的,所以这里提供一下代码,供参考:

[cpp] view plain copy

  1. /**
  2. * 基准点排序
  3. *
  4. * T = O(n)
  5. *
  6. */
  7. int pivotLoc(int *arr, int bt, int ed)
  8. {
  9. int stand;
  10. stand = arr[bt];
  11. while (bt < ed) {
  12. while (bt < ed && arr[ed] >= stand) ed —;
  13. if (bt < ed) arr[bt ++] = arr[ed];
  14. while (bt < ed && arr[bt] <= stand) bt ++;
  15. if (bt < ed) arr[ed —] = arr[bt];
  16. }
  17. arr[bt] = stand;
  18. return bt;
  19. }
  20. /**
  21. * 快排入口代码,递归策略
  22. *
  23. * T = O(nlogn)
  24. *
  25. */
  26. void quickSort(int *arr, int bt, int ed)
  27. {
  28. int pivot;
  29. if (bt < ed) {
  30. pivot = pivotLoc(arr, bt, ed);
  31. quickSort(arr, bt, pivot - 1);
  32. quickSort(arr, pivot + 1, ed);
  33. }
  34. }

优化

快排的平均时间复杂度是O(nlogn),但是考虑一下最坏的情况:

假设给定的排序序列是逆序,例如5、4、3、2、1,然后用上述快排代码进行从小到大排序,很明显,快排从O(nlogn)降到了O(n^2),如何避免这种情况呢?

解答:基准点的随机选取,我这里每次采用mid作为基准点

[cpp] view plain copy

  1. /**
  2. * 快排优化,随机选取基准点
  3. *
  4. */
  5. void optimizeSort(int *arr, int bt, int ed)
  6. {
  7. int mid = bt + ((ed - bt) >> 1);
  8. // 不使用额外空间,进行两数互换
  9. if (arr[bt] != arr[mid]) {
  10. arr[bt] = arr[bt] ^ arr[mid];
  11. arr[mid] = arr[bt] ^ arr[mid];
  12. arr[bt] = arr[bt] ^ arr[mid];
  13. }
  14. }
  15. /**
  16. * 基准点排序
  17. *
  18. * T = O(n)
  19. *
  20. */
  21. int pivotLoc(int *arr, int bt, int ed)
  22. {
  23. int stand;
  24. // 快排优化
  25. if (bt < ed) {
  26. optimizeSort(arr, bt, ed);
  27. }
  28. stand = arr[bt];
  29. while (bt < ed) {
  30. while (bt < ed && arr[ed] >= stand) ed —;
  31. if (bt < ed) arr[bt ++] = arr[ed];
  32. while (bt < ed && arr[bt] <= stand) bt ++;
  33. if (bt < ed) arr[ed —] = arr[bt];
  34. }
  35. arr[bt] = stand;
  36. return bt;
  37. }
  38. /**
  39. * 快排入口代码,递归策略
  40. *
  41. * T = O(nlogn)
  42. *
  43. */
  44. void quickSort(int *arr, int bt, int ed)
  45. {
  46. int pivot;
  47. if (bt < ed) {
  48. pivot = pivotLoc(arr, bt, ed);
  49. quickSort(arr, bt, pivot - 1);
  50. quickSort(arr, pivot + 1, ed);
  51. }
  52. }

非递归法

  1. /*
  2. *BLOG:http://blog.csdn.net/wdzxl198
  3. *AUTHOR:Atlas
  4. *EMAIL:wdzxl198@163.com
  5. */
  6. #include<iostream>
  7. #include<stack>
  8. using namespace std;
  9. int Partition(int array[],int lhs,int rhs)
  10. {
  11. int x = array[rhs];
  12. int i = lhs - 1;
  13. for(int j=lhs;j<=rhs-1;j++)
  14. {
  15. if(array[j] <= x)
  16. {
  17. ++i;
  18. std::swap(array[i],array[j]);
  19. }
  20. }
  21. std::swap(array[i+1],array[rhs]);
  22. return i+1;
  23. }
  24. void QuickSort(int *arr,int left,int right)
  25. {
  26. stack<int> st;
  27. if(left < right)
  28. {
  29. int mid = Partition(arr,left,right);
  30. if(left < mid-1)
  31. {
  32. st.push(left);
  33. st.push(mid-1);
  34. }
  35. if(mid+1 < right)
  36. {
  37. st.push(mid+1);
  38. st.push(right);
  39. }
  40. while(!st.empty())
  41. {
  42. int q = st.top();
  43. st.pop();
  44. int p = st.top();
  45. st.pop();
  46. mid = Partition(arr,p,q);
  47. if(p < mid-1)
  48. {
  49. st.push(p);
  50. st.push(mid-1);
  51. }
  52. if(mid+1 < q)
  53. {
  54. st.push(mid+1);
  55. st.push(q);
  56. }
  57. }
  58. }
  59. else
  60. return;
  61. }
  62. int main()
  63. {
  64. int a[10] ={3,7,6,4,0,2,9,8,1,5};
  65. for(int i=0;i<10;i++)
  66. cout<<a[i]<<" ";
  67. cout<<endl;
  68. cout<<"快速排序:";
  69. QuickSort(a,0,9);
  70. for(int i=0;i<10;i++)
  71. cout<<a[i]<<" ";
  72. cout<<endl;
  73. system("PAUSE");
  74. return 0;
  75. }

发表评论

表情:
评论列表 (有 0 条评论,296人围观)

还没有评论,来说两句吧...

相关阅读