一句话说透数据结构里面的快速排序,如何优化

124 阅读2分钟

一句话总结:
快速排序的优化就像给赛车调校——选好基准(轮胎),小规模换策略(弯道用漂移),处理重复零件(三向切分),让排序速度更快更稳!


一、基础版快速排序(先跑起来)

原理:  选基准、分区、递归处理左右

fun quickSortBasic(arr: IntArray, low: Int = 0, high: Int = arr.size - 1) {
    if (low < high) {
        val pivotIndex = partition(arr, low, high)
        quickSortBasic(arr, low, pivotIndex - 1)
        quickSortBasic(arr, pivotIndex + 1, high)
    }
}

private fun partition(arr: IntArray, low: Int, high: Int): Int {
    val pivot = arr[high] // 选最后一个元素为基准(有优化空间!)
    var i = low - 1
    for (j in low until high) {
        if (arr[j] <= pivot) {
            i++
            arr.swap(i, j)
        }
    }
    arr.swap(i + 1, high)
    return i + 1
}

// 交换扩展函数
fun IntArray.swap(i: Int, j: Int) {
    val temp = this[i]
    this[i] = this[j]
    this[j] = temp
}

二、优化策略(让赛车更快)

优化 1:随机选择基准(避免最坏情况)

private fun partitionOptimized(arr: IntArray, low: Int, high: Int): Int {
    // 随机选基准并与末尾交换
    val randomIndex = (low..high).random()
    arr.swap(randomIndex, high)
    return partition(arr, low, high) // 继续用基础版分区
}

优化 2:小数组用插入排序(减少递归开销)

fun quickSortOptimized(arr: IntArray, low: Int = 0, high: Int = arr.size - 1) {
    if (high - low < 10) { // 小数组阈值设为10
        insertionSort(arr, low, high)
        return
    }
    val pivotIndex = partitionOptimized(arr, low, high)
    quickSortOptimized(arr, low, pivotIndex - 1)
    quickSortOptimized(arr, pivotIndex + 1, high)
}

private fun insertionSort(arr: IntArray, low: Int, high: Int) {
    for (i in low + 1..high) {
        val key = arr[i]
        var j = i - 1
        while (j >= low && arr[j] > key) {
            arr[j + 1] = arr[j]
            j--
        }
        arr[j + 1] = key
    }
}

优化 3:三向切分(处理大量重复元素)

fun quickSortThreeWay(arr: IntArray, low: Int = 0, high: Int = arr.size - 1) {
    if (high <= low) return
    
    // 初始化三个指针
    var lt = low
    var gt = high
    val pivot = arr[low]
    var i = low + 1
    
    while (i <= gt) {
        when {
            arr[i] < pivot -> arr.swap(lt++, i++)
            arr[i] > pivot -> arr.swap(i, gt--)
            else -> i++
        }
    }
    // 递归处理左右
    quickSortThreeWay(arr, low, lt - 1)
    quickSortThreeWay(arr, gt + 1, high)
}

三、测试用例(验车)

fun main() {
    // 测试用例1:普通乱序数组
    val arr1 = intArrayOf(3, 1, 4, 1, 5, 9, 2, 6)
    quickSortOptimized(arr1)
    println(arr1.contentToString()) // [1, 1, 2, 3, 4, 5, 6, 9]

    // 测试用例2:已排序数组(测试最坏情况优化)
    val arr2 = intArrayOf(1, 2, 3, 4, 5)
    quickSortOptimized(arr2)
    println(arr2.contentToString()) // [1, 2, 3, 4, 5]

    // 测试用例3:大量重复元素
    val arr3 = intArrayOf(2, 2, 1, 1, 3, 3, 3)
    quickSortThreeWay(arr3)
    println(arr3.contentToString()) // [1, 1, 2, 2, 3, 3, 3]

    // 测试用例4:空数组和单元素数组
    val arr4 = intArrayOf()
    quickSortOptimized(arr4) // 无异常
    val arr5 = intArrayOf(5)
    quickSortOptimized(arr5)
    println(arr5.contentToString()) // [5]
}

四、优化效果对比

场景基础版随机基准小数组优化三向切分
完全有序数组O(n²)O(n log n)O(n log n)O(n log n)
大量重复元素O(n²)O(n log n)O(n log n)O(n)
随机数据O(n log n)O(n log n)O(n log n)O(n log n)

五、口诀

快速排序要优化,
随机基准是妙法。
小数组改插入排,
重复元素三向切!

弯道超车靠调校,
数据再大也不怕! 🚀