基础篇9 # 排序:冒泡排序(Bubble Sort)插入排序(Insertion Sort)选择排序(Selection Sort)

Posted 凯小默

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基础篇9 # 排序:冒泡排序(Bubble Sort)插入排序(Insertion Sort)选择排序(Selection Sort)相关的知识,希望对你有一定的参考价值。

说明

【数据结构与算法之美】专栏学习笔记

如何分析一个排序算法?

1、排序算法的执行效率

  • 最好情况、最坏情况、平均情况时间复杂度
  • 时间复杂度的系数、常数 、低阶
  • 比较次数和交换(或移动)次数

2、排序算法的内存消耗

3、排序算法的稳定性

原地排序(Sorted in place):就是特指空间复杂度是 O(1) 的排序算法。

稳定性度量指标:如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变,这种排序算法叫作稳定的排序算法;如果前后顺序发生变化,那对应的排序算法就叫作不稳定的排序算法

冒泡排序(Bubble Sort)

冒泡排序是一种简单的排序算法,它重复地走访过要排序的数列,每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求。如果不满足就让它俩互换。

// 冒泡排序,a表示数组,n表示数组大小
public void bubbleSort(int[] a, int n) 
  if (n <= 1) return;
 
 for (int i = 0; i < n; ++i) 
    // 提前退出冒泡循环的标志位
    boolean flag = false;
    for (int j = 0; j < n - i - 1; ++j) 
      if (a[j] > a[j+1])  // 交换
        int tmp = a[j];
        a[j] = a[j+1];
        a[j+1] = tmp;
        flag = true;  // 表示有数据交换      
      
    
    if (!flag) break;  // 没有数据交换,提前退出
  

可以查看排序的可视化演示

有序度

有序度是数组中具有有序关系的元素对的个数。

有序元素数学表达式表示如下:

有序元素对:a[i] <= a[j], 如果 i < j。

比如:2,4,3,1,5,6,这组数据

有序元素有:

(2, 4) (2, 3) (2, 5) (2, 6)
(4, 5) (4, 6)
(3, 5) (3, 6)
(1, 5) (1, 6)
(5, 6)

所以上面数据组的有序度就是11。

比如 6,5,4,3,2,1,有序度是 0;对于一个完全有序的数组,有序度就是 n(n-1)/2*。全有序的数组的有序度叫作满有序度

逆序度

逆序元素对:a[i] > a[j], 如果i < j。

逆序度 = 满有序度 - 有序度

下面用 4,5,6,3,2,1 这组数据来对比一下冒泡过程的有序度跟逆序度:

冒泡次数冒泡后结果有序度逆序度
初始状态4,5,6,3,2,1312
第 1 次冒泡4,5,3,2,1,6️⃣69
第 2 次冒泡4,3,2,1,5️⃣,6️⃣96
第 3 次冒泡3,2,1,4️⃣,5️⃣,6️⃣123
第 4 次冒泡2,1,3️⃣,4️⃣,5️⃣,6️⃣141
第 5 次冒泡1,2️⃣,3️⃣,4️⃣,5️⃣,6️⃣150

冒泡排序包含两个操作原子,比较和交换。每交换一次,有序度就加 1。对于包含 n 个数据的数组进行冒泡排序,平均情况下,需要 n*(n-1)/4 次交换操作,平均情况下的时间复杂度就是 O( n 2 n^2 n2)。

插入排序(Insertion Sort)

插入排序是一种简单的排序算法,它的基本思想是:将一个记录插入到已排好序的有序表中,从而得到一个新的记录数增1的有序表。

插入算法的核心思想:将数组中的数据分为已排序区间和未排序区间两个区间,然后初始已排序区间只有一个元素,就是数组的第一个元素。再取未排序区间中的元素,在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。重复这个过程,直到未排序区间中元素为空,算法结束。

例子:4,5,6,1,3,2 数据进行插入排序,逆序数为10。

插入排序包含两种操作,一种是元素的比较,一种是元素的移动,移动操作的次数总是固定的,就等于逆序度。

// 插入排序,a表示数组,n表示数组大小
public void insertionSort(int[] a, int n) 
  if (n <= 1) return;

  for (int i = 1; i < n; ++i) 
    int value = a[i];
    int j = i - 1;
    // 查找插入的位置
    for (; j >= 0; --j) 
      if (a[j] > value) 
        a[j+1] = a[j];  // 数据移动
       else 
        break;
      
    
    a[j+1] = value; // 插入数据
  

有点晕的同学可以查看排序的可视化演示,选择插入排序,就能清晰的看到过程效果

现实生活里就有这样的例子,打扑克的时候,整理牌用到的思路其实就是插入排序,牌堆就是未排序区间,手中已摸的牌就是已排序区间。每一次抽牌,就根据摸到的牌的大小从左往右,或者从右往左对比,放到恰当的位置。

选择排序(Selection Sort)

选择排序算法的实现思路有点类似插入排序,但选择排序每次会从未排序区间中找到最小的元素,将其放到已排序区间的末尾。

选择排序原理示意图:可以查看排序的可视化演示,选择选择排序,就能清晰的看到过程效果

总结

总的来说,冒泡排序的数据交换要比插入排序的数据移动要复杂,相对于冒泡排序和插入排序,选择排序不稳定,就稍微逊色一点。

空间复杂度是否原地排序是否稳定最好时间复杂度最坏时间复杂度平均时间复杂度
冒泡排序O(1)✔️✔️O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)
插入排序O(1)✔️✔️O(n)O( n 2 n^2 n2)O( n 2 n^2 n2)
选择排序O(1)✔️O( n 2 n^2 n2)O( n 2 n^2 n2)O( n 2 n^2 n2)

以上是关于基础篇9 # 排序:冒泡排序(Bubble Sort)插入排序(Insertion Sort)选择排序(Selection Sort)的主要内容,如果未能解决你的问题,请参考以下文章

大话数据结构----冒泡排序Bubble sort

冒泡排序Bubble sort

Java中的经典算法之冒泡排序(Bubble Sort)

Java中的经典算法之冒泡排序(Bubble Sort)

Java中的经典算法之冒泡排序(Bubble Sort)

冒泡排序 (Bubble Sort)