快速排序

ByWhat'sUs

快速排序

如果要排序数据序列中下标从 p 到 r 之间的一组数据,我们选择 p 到 r 之间的任意一个数据作为 pivot(分区点),假设对应下标是 q

遍历 p 到 r 之间的数据,将小于 pivot 的放到左边,将大于 pivot 的放到右边,将 pivot 放到中间。经过这一步骤之后,数据序列 p 到 r 之间的数据就被分成了三个部分,前面 p 到 q-1 之间都是小于 pivot 的,中间是 pivot,后面的 q+1 到 r 之间是大于 pivot 的。

根据分治、递归的处理思想,我们可以用递归排序下标从 p 到 q-1 之间的数据和下标从 q+1 到 r 之间的数据,直到区间缩小为 1,就说明所有的数据都有序了,而且你可以看到我们不需要像归并排序那样做合并操作,也就不需要额外的内存空间,在时间复杂度和归并排序一样的情况下,有着更好的空间复杂度表现。

package main

import "fmt"

// 快速排序入口函数
func quickSort(nums []int, p int, r int) {
    // 递归终止条件
    if p >= r {
        return
    }
    // 获取分区位置
    q := partition(nums, p, r)
    // 递归分区(排序是在定位 pivot 的过程中实现的)
    quickSort(nums, p, q - 1)
    quickSort(nums, q + 1, r)
}

// 定位 pivot
func partition(nums []int, p int, r int) int {
    // 以当前数据序列最后一个元素作为初始 pivot
    pivot := nums[r]
    // 初始化 i、j 下标
    i := p
    // 后移 j 下标的遍历过程
    for j := p; j < r; j++ {
        // 将比 pivot 小的数丢到 [p...i-1] 中,剩下的 [i...j] 区间都是比 pivot 大的
        if nums[j] < pivot {
            // 互换 i、j 下标对应数据
            nums[i], nums[j] = nums[j], nums[i]
            // 将 i 下标后移一位
            i++
        }
    }

    // 最后将 pivot 与 i 下标对应数据值互换
    // 这样一来,pivot 就位于当前数据序列中间,i 也就是 pivot 值对应的下标
    nums[i], nums[r] = pivot, nums[i]
    // 返回 i 作为 pivot 分区位置
    return i
}

func main() {
    nums := []int{4, 5, 6, 7, 8, 3, 2, 1}
    quickSort(nums, 0, len(nums) - 1)
    fmt.Println(nums)
}

性能分析

  • 快速排序是原地排序算法,时间复杂度是 O(nlogn),这个时间复杂度数据量越大,越优于 O(n2)。
  • 但是快速排序也有其缺点,因为涉及到数据的交换,有可能破坏原来相等元素的位置排序,所以是不稳定的排序算法。

About the author

What'sUs administrator

Leave a Reply

PHP Code Snippets Powered By : XYZScripts.com