鸡尾酒排序,也称双向冒泡排序或摇动排序,是冒泡排序的一种改进变体。它的名字来源于调酒师摇动鸡尾酒的动作——来回摇动。该算法的具体发明者已不可考,但它在 20 世纪 70 年代开始出现在计算机科学教材中。鸡尾酒排序的设计初衷是解决冒泡排序中"乌龟"问题——较小的元素在数组末尾时,需要很多轮才能移动到正确位置。
鸡尾酒排序与冒泡排序类似,但它在每一轮中先从左到右进行冒泡(将最大元素移到最后),然后从右到左进行冒泡(将最小元素移到最前)。这种双向遍历可以更快地将小的元素移动到数组前面。
public class CocktailSort {
/**
* 鸡尾酒排序
*/
public static void sort(int[] arr) {
int left = 0;
int right = arr.length - 1;
boolean swapped = true;
while (left < right && swapped) {
swapped = false;
// 从左到右冒泡,将最大元素移到 right 位置
for (int i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
swapped = true;
}
}
right--;
if (!swapped) break;
swapped = false;
// 从右到左冒泡,将最小元素移到 left 位置
for (int i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
swap(arr, i, i - 1);
swapped = true;
}
}
left++;
}
}
/**
* 鸡尾酒排序(优化版本,记录最后一次交换位置)
*/
public static void sortOptimized(int[] arr) {
int left = 0;
int right = arr.length - 1;
int lastSwapLeft = 0;
int lastSwapRight = arr.length - 1;
while (left < right) {
// 从左到右
int newRight = left;
for (int i = left; i < right; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
newRight = i;
}
}
right = newRight;
if (left >= right) break;
// 从右到左
int newLeft = right;
for (int i = right; i > left; i--) {
if (arr[i] < arr[i - 1]) {
swap(arr, i, i - 1);
newLeft = i;
}
}
left = newLeft;
}
}
/**
* 鸡尾酒排序(泛型版本)
*/
public static <T extends Comparable<T>> void sortGeneric(T[] arr) {
int left = 0;
int right = arr.length - 1;
boolean swapped = true;
while (left < right && swapped) {
swapped = false;
for (int i = left; i < right; i++) {
if (arr[i].compareTo(arr[i + 1]) > 0) {
T temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
swapped = true;
}
}
right--;
if (!swapped) break;
swapped = false;
for (int i = right; i > left; i--) {
if (arr[i].compareTo(arr[i - 1]) < 0) {
T temp = arr[i];
arr[i] = arr[i - 1];
arr[i - 1] = temp;
swapped = true;
}
}
left++;
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
| 指标 | 最好情况 | 最坏情况 | 平均情况 |
|---|---|---|---|
| 时间复杂度 | O(n) | O(n²) | O(n²) |
| 空间复杂度 | O(1) | O(1) | O(1) |
| 比较次数 | n-1 | n(n-1)/2 | n²/2 |
| 交换次数 | 0 | n(n-1)/2 | n²/4 |
鸡尾酒排序是稳定的排序算法,也是原地排序。相比普通冒泡排序,鸡尾酒排序在最好的情况下可以减少一半的比较次数,特别适合数据基本有序但小的元素在数组末尾的场景。