js冒泡排序时间复杂度,O(n²)详解与优化


JavaScript 冒泡排序时间复杂度 O(n²) 详解与优化

冒泡排序是一种简单直观的排序算法,其基本思想是通过重复遍历待排序的数组,比较相邻的两个元素,如果它们的顺序错误就交换它们的位置,直到整个数组有序。冒泡排序的时间复杂度为 O(n²),这意味着在最坏的情况下,其执行时间与 n² 成正比。本文将详细解释冒泡排序的时间复杂度,并探讨一些优化方法。

冒泡排序的基本原理

冒泡排序的基本步骤如下:

1. 遍历数组:从数组的第一个元素开始,依次比较相邻的两个元素。

2. 比较与交换:如果前一个元素大于后一个元素(对于升序排序),则交换它们的位置。

3. 重复遍历:重复上述步骤,直到整个数组有序。

例如,对于数组 `[5, 3, 8, 4, 1]`,冒泡排序的过程如下:

1. 第一轮遍历:

- 比较 5 和 3,交换得到 `[3, 5, 8, 4, 1]`

- 比较 5 和 8,不交换

- 比较 8 和 4,交换得到 `[3, 5, 4, 8, 1]`

- 比较 8 和 1,交换得到 `[3, 5, 4, 1, 8]`

2. 第二轮遍历:

- 比较 3 和 5,不交换

- 比较 5 和 4,交换得到 `[3, 4, 5, 1, 8]`

- 比较 5 和 1,交换得到 `[3, 4, 1, 5, 8]`

- 比较 5 和 8,不交换

3. 第三轮遍历:

- 比较 3 和 4,不交换

- 比较 4 和 1,交换得到 `[3, 1, 4, 5, 8]`

- 比较 4 和 5,不交换

4. 第四轮遍历:

- 比较 3 和 1,交换得到 `[1, 3, 4, 5, 8]`

- 比较 3 和 4,不交换

5. 第五轮遍历:

- 比较 1 和 3,不交换

此时数组已经有序,排序完成。

时间复杂度 O(n²) 的分析

冒泡排序的时间复杂度可以通过分析其执行次数来理解。假设数组有 n 个元素,那么冒泡排序的执行次数可以分为两部分:

1. 遍历次数:冒泡排序需要进行 n-1 轮遍历。第一轮遍历 n-1 次比较,第二轮 n-2 次,依此类推,最后一轮 1 次比较。总的比较次数为:

[

(n-1) + (n-2) + cdots + 1 = frac{n(n-1)}{2}

]

这部分的时间复杂度为 O(n²)。

2. 交换次数:每次比较后,如果需要交换元素,则执行交换操作。交换操作的次数与比较次数相同,因此交换次数也是 O(n²)。

在最坏的情况下,即数组完全逆序时,冒泡排序需要进行最多的比较和交换操作,时间复杂度为 O(n²)。

在最好的情况下,即数组已经有序时,冒泡排序只需要进行一轮遍历,比较次数为 n-1,时间复杂度为 O(n)。但冒泡排序的最好时间复杂度仍然是 O(n),因为即使数组已经有序,它仍然会进行不必要的比较和交换操作。

冒泡排序的优化

1. 标志位优化:在每一轮遍历中,引入一个标志位,用于标记是否发生了交换。如果在某一轮遍历中没有发生交换,说明数组已经有序,可以提前终止排序。这个优化可以使得最好情况下的时间复杂度降低到 O(n)。

javascript

function bubbleSort(arr) {

let n = arr.length;

for (let i = 0; i < n - 1; i++) {

let swapped = false;

for (let j = 0; j < n - 1 - i; j++) {

if (arr[j] > arr[j + 1]) {

[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];

swapped = true;

}

}

if (!swapped) {

break;

}

}

return arr;

}

2. 双向冒泡排序(鸡尾酒排序):双向冒泡排序在每一轮遍历中,先从前往后进行一次冒泡,再从后往前进行一次冒泡。这样可以减少遍历的次数,提高效率。

javascript

function cocktailSort(arr) {

let n = arr.length;

let swapped = true;

let start = 0;

let end = n - 1;

while (swapped) {

swapped = false;

for (let i = start; i < end; i++) {

if (arr[i] > arr[i + 1]) {

[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];

swapped = true;

}

}

if (!swapped) {

break;

}

swapped = false;

end--;

for (let i = end - 1; i >= start; i--) {

if (arr[i] > arr[i + 1]) {

[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];

swapped = true;

}

}

start++;

}

return arr;

}

3. 选择合适的数据结构