图解冒泡排序

134 阅读2分钟

冒泡排序

冒泡排序是排序算法的一种,通过比较和交换两个相邻的元素,直到按照想要的顺序(从小到大或从大到小)为止。简言之:两两排序。

冒泡排序

const bubbleSort = (array) => {
    const size = array.length;
    for(let i = 0; i < size - 1; i++) {
        for (let j = 0; j < size- 1; j++) {
            if (array[j] > array[j + 1]) {
                [array[j], array[j + 1]] = [array[j + 1], array[j]];
            }
        }
    }
    return array;
};

冒泡排序的工作原理

假如我们将要将元素升序排序

  1. 第一次迭代(比较和交换)

    1.1 从第一个索引开始,比较第一个和第二个元素

    1.2 如果第一个元素比第二个元素大,交换它们

    1.3 比较第二个和第三个元素,如果第二个比第三个大,交换它们

    1.4 重复以上步骤,直到最后一个元素。

比较和交换元素

  1. 其余的迭代

剩余的迭代同第一次迭代步骤一样。

每次迭代后,未排序元素中最大元素被放在末尾。

最大的元素在末尾

每一次迭代都会进行比较,直到最后一个未排序的元素为止。

比较相邻元素

当所有未排序的元素都放在正确的位置时,这个数组便是有序的了。

如果所有元素都是有序的

冒泡排序的代码

const bubbleSort = (array) => {
    const size = array.length;
    for(let i = 0; i < size - 1; i++) {
        for (let j = 0; j < size- 1; j++) {
            if (array[j] > array[j + 1]) {
                [array[j], array[j + 1]] = [array[j + 1], array[j]];
            }
        }
    }
    return array;
};

冒泡排序优化

我们仔细观察上面的代码可以发现,即使数组已经是有序的情况下,依然会进行比较。这增加了代码的执行时间。

这里我们可以进行优化:引入一个变量 swapped,如果元素进行了交换,设置它的值为 true,否则为 false

如果一轮迭代结束后,没有交换, swapped 的值是 fasle, 意味着元素已经是有序的了,就不需要再执行其他的迭代了。

优化后的冒泡排序代码

const bubbleSort = (array) => {
    let size = array.length;
    for (let i = 0; i < size - 1; i++) {
        let swapped = false;
        for (let j = 0; j < size - 1; j++) {
            if (array[j] > array[j + 1]) {
                //
                [array[j], array[j + 1]] = [array[j + 1], array[j]];
                swapped = true;
            }
        }
        if (!swapped) break;
    }
};

复杂度分析:

名字最好平均最坏内存是否稳定
冒泡排序O(n)O(n^2)O(n^2)O(1)

复杂度分析详解

时间复杂度

冒泡排序对比相邻的元素:

每一轮对比的次数
第一轮迭代(n - 1)
第二轮迭代(n - 2)
............
最后一轮迭代----1

因此,对比的次数为:

(n-1) + (n-2) + (n-3) + ...... + 1 = n(n-1)/2

结果相当于 n^2,因此,时间复杂度为 O(n^2)

我们也可以通过观察代码,冒泡排序经过两轮循环,因此,时间复杂度为 O(n^2)

空间复杂度

  • 空间复杂度为 O(1),因为需要一个额外的变量用于交换
  • 优化过后的空间复杂度为 O(2),因为多用了一个额外变量。

注: JavaScript 中使用解构赋值的方式进行交换,我不清楚底层代码如何实现的,如果有大佬知道可以留言,欢迎探讨。