双向冒泡排序
实现双向冒泡排序算法(鸡尾酒排序)
问题
实现双向冒泡排序(Cocktail Sort),也叫鸡尾酒排序。
解答
双向冒泡排序是普通冒泡排序的改进版。普通冒泡只从左到右单向遍历,而双向冒泡会交替从左到右、从右到左遍历,能更快地将两端的元素归位。
function cocktailSort(arr) {
let left = 0;
let right = arr.length - 1;
while (left < right) {
// 从左到右,把最大值冒泡到右边
for (let i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
}
}
right--; // 最大值已归位,右边界左移
// 从右到左,把最小值冒泡到左边
for (let i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
[arr[i], arr[i - 1]] = [arr[i - 1], arr[i]];
}
}
left++; // 最小值已归位,左边界右移
}
return arr;
}
// 测试
console.log(cocktailSort([5, 3, 8, 4, 2])); // [2, 3, 4, 5, 8]
console.log(cocktailSort([1, 2, 3, 4, 5])); // [1, 2, 3, 4, 5]
console.log(cocktailSort([5, 4, 3, 2, 1])); // [1, 2, 3, 4, 5]
优化版本:提前终止
function cocktailSortOptimized(arr) {
let left = 0;
let right = arr.length - 1;
let swapped = true;
while (left < right && swapped) {
swapped = false;
// 从左到右
for (let i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
[arr[i], arr[i + 1]] = [arr[i + 1], arr[i]];
swapped = true;
}
}
right--;
// 如果没有交换,说明已经有序
if (!swapped) break;
// 从右到左
for (let i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
[arr[i], arr[i - 1]] = [arr[i - 1], arr[i]];
swapped = true;
}
}
left++;
}
return arr;
}
关键点
- 双向遍历:交替从左到右、从右到左,每轮同时确定最大和最小值的位置
- 边界收缩:每完成一个方向的遍历,对应边界向内收缩
- 提前终止:如果某轮没有发生交换,说明数组已有序,可以提前退出
- 时间复杂度:平均 O(n²),但对于部分有序的数组比普通冒泡更快
- 空间复杂度:O(1),原地排序
目录