1、算法思想
比较两个相邻的元素,将值小元素的向前移,将值大的元素向后移。
首先第一个元素和第二个元素比较,如果第一个大,则二者交换,否则不交换;然后第二个元素和第三个元素比较,如果第二个大,则二者交换,否则不交换…一直执行下去,最终最大的那个元素被交换到最后,一趟冒泡排序完成。最坏的情况是初始排序是逆序的。
2、算法过程
原始序列:24、13、 75、44、59、93、84、47
第一趟的排序过程:
-
1号和2号比较 24 > 13,交换
结果:13、 24、75、44、59、93、84、47 -
2号和3号比较 24 < 75,不交换
结果:13、 24、75、44、59、93、84、47 -
3号和4号比较 75 > 44,交换
结果:13、 24、44、75、59、93、84、47 -
4号和5号比较 75 > 59,交换
结果:13、 24、44、59、75、93、84、47 -
5号和6号比较 75 < 93,不交换
结果:13、 24、44、59、75、93、84、47 -
6号和7号比较 93 > 84,交换
结果:13、 24、44、59、75、84、93、47 -
7号和8号比较 93 > 47,交换
结果:13、 24、44、59、75、84、47、93
第一趟排序结束,依次执行第二趟、第三趟…,直到排序过程没有元素位置改变或最后一趟排序完成,跳出循环。
3、算法复杂度
若数组的初始状态是正序的,一趟扫描即可完成排序。所需的比较次数 C 和移动次数 M 均达到最小值:
Cmin = n -1
Mmin = 0
所以,冒泡排序最好的时间复杂度为 O(n) 。
若数组的初始状态是逆序的,需要进行 n - 1 趟排序。每趟排序要进行 n - i 次比较(1≤i≤n-1),且每次比较都必须移动三次以交换位置。在这种情况下,比较和移动次数均达到最大值:
Cmax = n * (n -1) / 2 = O(n2)
Mmax = 3 * n * (n -1) / 2 = O(n2)
冒泡排序的最坏时间复杂度为 O(n2)。
综上,冒泡排序的平均时间复杂度为 O(n2)。
4、算法稳定性
冒泡排序就是把小的元素往前调,把大的元素往后调。比较的是相邻的两个元素,交换也发生在这两个元素之间。所以,如果两个元素相等,是不会交换的。
如果两个相等的元素没有相邻,即使通过前面的两两交换把这两个相邻起来,也不会交换,所以相同元素的前后顺序不会发生改变。
因此,冒泡排序是一种稳定排序算法。
5、算法实现
function bubbleSort(arr) {
const len = arr.length;
for (let i = 0; i < len - 1; i++) {
let swap = false;
for (let j = 0; j < len - 1 - i; j++) {
if (arr[j] > arr[j+1]) {
[arr[j], arr[j+1]] = [arr[j+1], arr[j]];
swap = true;
}
}
if (!swap) {
break;
}
}
}