• 排序算法的稳定性


    什么是排序算法的稳定性?

    排序算法的稳定性:

    假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i] = r[j],且 r[i] 在 r[j] 之前,而在排序后的序列中,r[i] 仍在 r[j] 之前,则称这种排序算法是稳定的;否则称为不稳定的。

    以下以冒泡排序和选择排序作为比较,分析排序算法的稳定性。

    冒泡排序

    一边比较一边向后两两交换,将最大值 / 最小值冒泡到最后一位;
    经过优化的写法:使用一个变量记录当前轮次的比较是否发生过交换,如果没有发生交换表示已经有序,不再继续排序;
    进一步优化的写法:除了使用变量记录当前轮次是否发生交换外,再使用一个变量记录上次发生交换的位置,下一轮排序时到达上次交换的位置就停止比较。

    1. public static void bubbleSort(int[] arr) {
    2. // 记录每轮冒泡是否发生了交换
    3. boolean swapped;
    4. for (int i = 0; i < arr.length - 1; i++) {
    5. swapped = false;
    6. for (int j = 0; j < arr.length - 1 - i; j++) {
    7. if (arr[j] > arr[j + 1]) {
    8. swap(arr, j, j + 1);
    9. swapped = true;
    10. }
    11. }
    12. // 如果没有发生过交换,直接退出循环
    13. if (!swapped) break;
    14. }
    15. }

    选择排序

    选择排序的思想是:双重循环遍历数组,每经过一轮比较,找到最小元素的下标,将其交换至首位。

    1. public static void selectionSort(int[] arr) {
    2. int minIndex;
    3. for (int i = 0; i < arr.length - 1; i++) {
    4. minIndex = i;
    5. for (int j = i + 1; j < arr.length; j++) {
    6. if (arr[minIndex] > arr[j]) {
    7. // 记录最小值的下标
    8. minIndex = j;
    9. }
    10. }
    11. // 将最小元素交换至首位
    12. int temp = arr[i];
    13. arr[i] = arr[minIndex];
    14. arr[minIndex] = temp;
    15. }
    16. }

    选择排序就好比第一个数字站在擂台上,大吼一声:“还有谁比我小?”。剩余数字来挨个打擂,如果出现比第一个数字小的数,则新的擂主产生。每轮打擂结束都会找出一个最小的数,将其交换至首位。经过 n-1 轮打擂,所有的数字就按照从小到大排序完成了。

    现在让我们思考一下,冒泡排序和选择排序有什么异同?

    相同点:

    都是两层循环,时间复杂度都为 O(n^2);
    都只使用有限个变量,空间复杂度 O(1)。
    不同点:

    冒泡排序在比较过程中就不断交换;而选择排序增加了一个变量保存最小值 / 最大值的下标,遍历完成后才交换,减少了交换次数。
    事实上,冒泡排序和选择排序还有一个非常重要的不同点,那就是:

    冒泡排序法是稳定的,选择排序法是不稳定的。

    排序算法的稳定性有什么意义?

    其实它只在一种情况下有意义:当要排序的内容是一个对象的多个属性,且其原本的顺序存在意义时,如果我们需要在二次排序后保持原有排序的意义,就需要使用到稳定性的算法。

    举个例子,如果我们要对一组商品排序,商品存在两个属性:价格和销量。当我们按照价格从高到低排序后,要再按照销量对其排序,这时,如果要保证销量相同的商品仍保持价格从高到低的顺序,就必须使用稳定性算法。

    当然,算法的稳定性与具体的实现有关。在修改比较的条件后,稳定性排序算法可能会变成不稳定的。如冒泡算法中,如果将「左边的数大于右边的数,则交换」这个条件修改为「左边的数大于或等于右边的数,则交换」,冒泡算法就变得不稳定了。

    同样地,不稳定排序算法也可以经过修改,达到稳定的效果。思考一下,选择排序算法如何实现稳定排序呢?

    实现的方式有很多种,这里给出一种最简单的思路:新开一个数组,将每轮找出的最小值依次添加到新数组中,选择排序算法就变成稳定的了。

    但如果将寻找最小值的比较条件由arr[minIndex] > arr[j]修改为arr[minIndex] >= arr[j],即使新开一个数组,选择排序算法依旧是不稳定的。所以分析算法的稳定性时,需要结合具体的实现逻辑才能得出结论,我们通常所说的算法稳定性是基于一般实现而言的。

  • 相关阅读:
    10.10作业
    一文读懂梯度下降
    限制LitstBox控件显示指定行数的最新数据(1/3)
    Windows 驱动开发 新手入门(四)
    NC20279 [SCOI2010]序列操作
    python如何操作mysql数据库
    docker环境,ubuntu18.04安装VTK8.2和PCL1.9.1
    1131. 绝对值表达式的最大值
    jxTMS设计思想之流程开发(二)
    【数据结构】AVL树(C++实现)
  • 原文地址:https://blog.csdn.net/carrie__yang/article/details/133806604