• 第八单元 排序算法8.1 常用排序算法


    第八单元 排序算法

    8.1 常用排序算法

    (1) 使用 STL 算法!

    平均时间:O(nlogn)
    头文件:<algorithm>
    ① 调用方法:sort(第一项的地址, 最后一项的地址+1);
    如 sort(&a[0],&a[n]);或 sort(a,a+n);
    注意,STL 的区间是左闭右开区间。
    ② 自定义规则的排序:有时排序的条件不止一个,或不方便对原数据进行排序,就需要自定义比较规则。
    这时需要建立一个函数,把“小于”解释明白。例如:

    1. bool cmp(const int &i, const int &j) {return w[i]<w[j];} // 自定义比较规则
    2. ……
    3. sort(a, a+n, cmp);

    cmp 要讲清 a[i]和 a[j]的比较方法。对于上面的代码,就是“如果 w[i]<w[j],那么 a[i]就排在 a[j]
    的前面”。

    (2) 快速排序!

    平均时间:O(nlogn)
    快速排序俗称“快排”,是基于比较的排序算法中最快的一种算法

    1. void quicksort(int *a, int start, int end)
    2. {
    3. int low=start, high=end;
    4. int temp, check=a[start];
    5. // 划分:把比check小的数据放到它的左边,把比check大的数放到它的右边。
    6. do
    7. {
    8. while (a[high]>=check&&low<high) high--; // 注意,不要写成“low<=high”!
    9. if (a[high]<check)
    10. temp=a[high], a[high]=a[low], a[low]=temp;
    11. while (a[low]<=check&&low<high) low++; // 注意,不要写成“low<=high”!
    12. if (a[low]>check)
    13. temp=a[high], a[high]=a[low], a[low]=temp;
    14. }
    15. while (low!=high);
    16. a[low]=check;
    17. low--,high++;
    18. // 递归:对已经划分好的两部分分别进行快速排序
    19. if (low>start) quicksort(a, start, low);
    20. if (high<end) quicksort(a, high, end);
    21. }

    快速排序的版本很多,上面只是众多版本中的一种。
    快速排序的三个优化方法:
    1. 规模很小时(如 end-start<10),使用插入排序代替快速排序。
    2. 使用栈模拟递归。
    3. 极端数据(如比较有序的数组)会使快速排序变慢,甚至退化为冒泡排序。可以采用“三者取中法”来解决这个问题:令 check 等于 a[start]、a[end]、a[(start+end)/2]中的中间值。
    第三种方法可以消除坏数据(基本有序的数据,它可以使快速排序退化为 O(n^2)时间)对排序的影响。

    (3) 归并排序

    时间复杂度:O(nlogn)
    注意:
    1. 其他排序算法的空间复杂度是 O(1),而归并排序的空间复杂度很大,为 O(n)。
    2. 下面的 end 是“末尾索引+1”,即数列末尾要留一个空位。

    1. int temp[N];
    2. void mergesort(int *a, int start, int end)
    3. {
    4. if (start+1>=end) return;
    5. // 划分阶段、递归
    6. int mid = start+(end-start)/2;
    7. mergesort(a, start, mid);
    8. mergesort(a, mid, end);
    9. // 将mid两侧的两个有序表合并为一个有序表。
    10. int p=start,q=mid,r=start;
    11. while (p<mid || q<end)
    12. if (q>=end || (p<mid && a[p]<=a[q]))
    13. temp[r++]=a[p++];
    14. else
    15. temp[r++]=a[q++];
    16. for (p=start;p<end;p++) a[p]=temp[p];
    17. }

    在(end-start)不太大时,可以用插入排序代替归并排序。
    归并排序还有另一种写法:开始复制的时候,把第二个子数组中元素的顺序颠倒了一下。

    1. int temp[N]; // “临时安置点”
    2. void mergesort(int *a, int start, int end)
    3. {
    4. if (start==end) return;
    5. int mid = start+(end-start)/2;
    6. mergesort(a, start, mid);
    7. mergesort(a, mid, end);
    8. // 合并
    9. for (int i=mid; i>=start; i--) temp[i]=a[i];
    10. for (int j=1;j<=end-mid;j++) temp[end-j+1]=a[j+mid];
    11. for (int i=start,j=end,k=start; k<=end; k++)
    12. if (temp[i]<temp[j])
    13. a[k]=temp[i++];
    14. else
    15. a[k]=temp[j--];
    16. }

    在(end-start)不太大时,也可以用插入排序代替归并排序。

  • 相关阅读:
    Python实现贝叶斯岭回归模型(BayesianRidge算法)并使用K折交叉验证进行模型评估项目实战
    用 VS Code 搞 Qt6:信号、槽,以及QObject
    java毕业生设计高校毕业生就业满意度调查统计系统计算机源码+系统+mysql+调试部署+lw
    沉睡者IT - 关于知乎好物赚钱方法都在这里了
    5年测开经验,领导却说:写的测试文档还不如应届生
    manifold.ext.rt manifold @Extension
    Docker详解(一)
    Java之POI导出Excel(一):单sheet
    【算法】网络最大流问题,三次尝试以失败告终
    CentOs程序环境准备
  • 原文地址:https://blog.csdn.net/zhengheda/article/details/125521990