Skip to content

鸡尾酒排序(Cocktail Sort) ​

鸡尾酒排序(Cocktail Sort),又称为双向冒泡排序(Bidirectional Bubble Sort)或鸡尾酒搅拌排序,是冒泡排序的一种变种。它双向扫描,一轮里既把较大的元素“沉”到数组右端,也把较小的元素“浮”到左端,比单向冒泡少走几轮。

1. 鸡尾酒排序的基本概念 ​

鸡尾酒排序的核心思想是:

  1. 双向扫描: 先从左到右扫一遍,再从右到左扫一遍,一轮里同时处理大值和小值,减少扫描的轮数。
  2. 相邻交换: 每次扫描都靠交换相邻的两个元素,把未排序的部分逐步理顺。

2. 鸡尾酒排序的算法步骤 ​

  1. 初始化: 设置两个指针,left 和 right,分别指向数组的开始和结束。

  2. 前向扫描(从左到右):

    • 从左到右扫描数组,将较大的元素移动到数组的右边(即末尾)。
    • 在每次交换时,更新右指针的位置,因为已经有序的部分不再需要参与排序。
  3. 后向扫描(从右到左):

    • 从右到左扫描数组,将较小的元素移动到数组的左边(即开头)。
    • 在每次交换时,更新左指针的位置,因为已经有序的部分不再需要参与排序。
  4. 重复过程: 不断重复前向扫描和后向扫描,直到整个数组有序。

3. 鸡尾酒排序的时间复杂度和空间复杂度 ​

  • 时间复杂度:

    • 最坏情况: $O(n^2)$,与冒泡排序相同。
    • 最佳情况: $O(n)$,如果数组已经有序,则只需一次前向和后向扫描。
    • 平均情况: $O(n^2)$,由于需要双向扫描,平均性能与冒泡排序类似。
  • 空间复杂度: $O(1)$,鸡尾酒排序是原地排序算法,不需要额外的存储空间。

4. 鸡尾酒排序的代码示例 ​

go
package main

import "fmt"

// 鸡尾酒排序
func cocktailSort(arr []int) {
    n := len(arr)
    if n <= 1 {
        return
    }

    // 初始化指针
    left, right := 0, n-1
    for left < right {
        // 前向扫描
        swapped := false
        for 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
        }

        // 后向扫描
        swapped = false
        for i := right; i > left; i-- {
            if arr[i] < arr[i-1] {
                arr[i], arr[i-1] = arr[i-1], arr[i]
                swapped = true
            }
        }
        left++
    }
}

func main() {
    arr := []int{5, 1, 4, 2, 8, 6, 3, 7}
    fmt.Println("Original array:", arr)
    cocktailSort(arr)
    fmt.Println("Sorted array:", arr)
}

5. 鸡尾酒排序的优缺点 ​

和单向冒泡比,鸡尾酒排序一轮里两头都排,部分有序的数据能少扫几轮,代价是要维护前后两个方向的扫描,实现比冒泡排序复杂。它最坏情况仍是 $O(n^2)$,大规模数据用它不划算。

总结 ​

鸡尾酒排序是双向的冒泡排序:一轮从左到右把大值沉下去,再从右到左把小值浮上来。已有序的数组一次前后扫描就能确认,复杂度 $O(n)$;排不好的数据仍是 $O(n^2)$,与冒泡排序打平。

参考资料 ​

同层页面 ​

相关页面 ​

Hello Golang