鸡尾酒排序-JS代码实现

207 阅读2分钟

鸡尾酒排序又称双向冒泡排序、鸡尾酒搅拌排序、搅拌排序、涟漪排序、来回排序或快乐小时排序, 是冒泡排序的一种变形。

如果您还不了解冒泡排序的话,请先浏览这篇文章: 冒泡排序

冒泡排序算法每一轮都是从左到右比较元素,进行 单向 的位置交换。
鸡尾酒排序比较和交换元素的过程是 双向 的。

假设有下面一种无序数列{2, 3, 4, 5, 6, 7, 8, 1},如果我们按照冒泡排序思想进行排序的话,如下:

我们会发现上述其实只有一个1是无序的,但是却需要遍历7次,这个性能就不高,那么鸡尾酒排序就可以解决上述的问题。

鸡尾酒排序又称双向排序,即先从左往右排序,那么下一轮就从右往左,循环往复。因此上面的排序如下:

第一轮:从左往右冒泡

第二轮:从右往左冒泡

第三轮:从左往右冒泡

此时已经是有序的,没有元素位置发生交换,排序结束。

js代码实现

// 从小到大排序
function cocktailSort(arr) {
    // n个数,单向需进行n-1趟操作,也就是i从0到n-2, 那么双向时i从0到(n-2)/2, 也就是i从0到 n/2-1, 所以限制 i<n/2 即可
  for (let i = 0; i < arr.length/2; i++) {  
    // 先从左往右排序,大的放在后面
    let isSorted = true;
    for (let j = i; j < arr.length - 1 - i; j++) {  // 注意初始条件是j = i 而不是j = 0, 因为进行1次双向排序后,最左侧就有1个值确定了顺序,下次排序不需要再从头开始
      if (arr[j] > arr[j+1]) {  // 左>右,则交换
        isSorted = false;
        let temp = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = temp;
      }
    }
    if (isSorted) {
      break;
    }

     // 再从右往左排序,小的放在前面
    isSorted = true;    // 这里注意将isSorted置为true, 因为如果上面从左往右排序时isSorted变为false; 而进行下面的从右往左排序时发现已经不需要交换,但isSorted仍然为false,则不能跳出循环,又白白从左往右比较了一趟
    for (let k = arr.length - 1 - i; k > i; k--) { // 注意初始条件是 k=arr.length-1-i; k > i。 因为进行1次双向排序后,最左侧和最右侧都有1个值确定了顺序,下次排序不需要这2个值参与比较了
      if (arr[k] < arr[k-1]) {  // 右<左,则交换
        isSorted = false;
        let temp = arr[k];
        arr[k] = arr[k-1];
        arr[k-1] = temp;
      }
    }
    if (isSorted) {
      break;
    }
  }
  return arr;
}

使用场景

鸡尾酒排序更加适合用在大多数元素已经是有序的前提下,可以减少排序的回合数。

如上述数组,使用鸡尾酒排序,用时仅为0.169ms

arr = [2, 3, 4, 5, 6, 7, 8, 1];
console.log("排序前", arr);
console.time("cocktailSort用时");
cocktailSort(arr);
console.timeEnd("cocktailSort用时");
console.log("排序后", arr);

image.png

而哪怕使用冒泡排序 一文中优化后的版本v3,用时仍需0.463ms

image.png

参考

zhuanlan.zhihu.com/p/125008445