【算法】冒泡排序

我想对于它每个学过C语言的都会了解,这可能是很多人接触的第一个排序算法。

一、基本思想

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

二、算法描述

冒泡排序算法的运作如下:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤1~3,直到没有任何一对数字需要比较。

三、代码实现

冒泡排序需要两个嵌套的循环。其中,外层循环移动游标;内层循环遍历游标及之后(或之前)的元素,通过两两交换的方式,每次只确保该内循环结束位置排序正确,然后内层循环周期结束,交由外层循环往后(或前)移动游标,随即开始下一轮内层循环,以此类推,直至循环结束。

/**
 * 冒泡排序
 *
 * @param array 待排序的数组
 */
public static void bubbleSort1(int[] array) {
    for (int i = array.length - 1; i > 0; i--) {
        // 将a[0...i]中最大的数据放在末尾
        for (int j = 0; j < i; j++) {
            if (array[j] > array[j + 1]) {
                // 交换a[j]和a[j+1]
                int temp= array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
            }
        }
    }
    display(array);
}

/**
 * 冒泡排序(改进版)
 *
 * @param array 待排序的数组
 */
public static void bubbleSort2(int[] array) {
    for (int i = array.length - 1; i > 0; i--) {
        boolean flag = true;            // 标记
        // 将a[0...i]中最大的数据放在末尾
        for (int j = 0; j < i; j++) {
            if (array[j] > array[j + 1]) {
                // 交换a[j]和a[j+1]
                int temp= array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
                flag = false;    // 若发生交换,则修改标记
            }
        }
        if (flag)
            break;
    }
    display(array);
}

/**
 * 遍历显示数组
 *
 * @param array 数组
 */
public static void display(int[] array) {
    for (int i = 0; i < array.length; i++) {
        System.out.print(array[i] + " ");
    }
    System.out.println();
}

冒泡排序解释:

冒泡排序是由两个for循环构成,第一个for循环的变量i表示总共需要多少轮比较,第二个for循环的变量j表示每轮参与比较的元素下标【0,1,......,length-i】,因为每轮比较都会出现一个最大值放在最右边,所以每轮比较后的元素个数都会少一个,这也是为什么j的范围是逐渐减小的。相信大家理解之后快速写出一个冒泡排序并不难。

四、冒泡排序性能分析

假设参与比较的数组元素个数为N,则第一轮排序有N-1次比较,第二轮有N-2次,如此类推,这种序列的求和公式为:

\[(N-1) + (N-2) + ... + 1 = N * (N-1) / 2 \]

N的值很大时,算法比较次数约为\(N^2/2\)次比较,忽略减1。

假设数据是随机的,那么每次比较可能要交换位置,可能不会交换,假设概率为50%,那么交换次数为\(N^2/4\)。不过如果是最坏的情况,初始数据是逆序的,那么每次比较都要交换位置。

交换和比较次数都和\(N^2\)成正比。由于常数不算大O表示法中,忽略24,那么冒泡排序运行都需要\(O(N^2)\)时间级别。

其实无论何时,只要看见一个循环嵌套在另一个循环中,我们都可以怀疑这个算法的运行时间为\(O(N^2)\)级,外层循环执行N次,内层循环对每一次外层循环都执行N次(或者几分之N次)。这就意味着大约需要执行\(N^2\)次某个基本操作。

以下是冒泡排序算法复杂度:

平均时间复杂度 最好情况 最坏情况 空间复杂度
O(n²) O(n) O(n²) O(1)

冒泡排序是最容易实现的排序,最坏的情况是每次都需要交换,共需遍历并交换将近\(n²/2\)次,时间复杂度为\(O(n²)\)。最佳的情况是内循环遍历一次后发现排序是对的,因此退出循环,时间复杂度为\(O(n)\)。平均来讲,时间复杂度为\(O(n²)\)。由于冒泡排序中只有缓存的temp变量需要内存空间,因此空间复杂度为常量\(O(1)\)

Tips: 由于冒泡排序只在相邻元素大小不符合要求时才调换他们的位置,它并不改变相同元素之间的相对顺序,因此它是稳定的排序算法。

posted @ 2022-06-11 15:30  夏尔_717  阅读(169)  评论(0编辑  收藏  举报