文章目录

  • 定义
  • 实现 之 左右指针法
  • 定义
  • 图示
  • 代码实现
  • 实现结果
  • 实现 之 填坑法
  • 图示
  • 实现
  • 结果
  • 性能
  • 时间复杂度
  • 空间复杂度
  • 算法稳定性


定义

快速排序(Quick Sort)是一种有效的排序算法。虽然算法在最坏的情况下运行时间为O(n^2),但由于平均运行时间为O(nlogn),并且在内存使用、程序实现复杂性上表现优秀,尤其是对快速排序算法进行随机化的可能,使得快速排序在一般情况下是最实用的排序方法之一。

快速排序被认为是当前最优秀的内部排序方法。

实现 之 左右指针法

定义

有一个数组a[size],左指针left指向下标为0的位置,右指针right指向下标为size-1的位置,同时标志key=a[right];left找a[left]>key的元素的下标,right找a[right] < key的元素的下标。left先开始走,当遇到比key大的数时,停下来,再由right开始走,当遇到比key小的数时,停下来。将left和right分别指的数交换,前提是left<right时,如果left>=right就说明一次快排结束。再将left指向的值与key值交换即可。此时的数组呈现出左边的值都比key值小,右边的值都比key值大。一次快排将数组分为两个区间,我们再对每个区间进行上述的排序方式。直到每个小区间已不能再划分。

图示

如图所示,将一组数据进行快速排序,比key大的都换到key的右边,比key小的都换到key的左边。

然后再继续进行排序,划为子问题进行解决:

python快速排序原理 快速排序法python_三数取中法

代码实现

class Sort:
    def quick_sort(self, data, left, right):
        if left < right:
            k_idx = self.partation(data, left, right)
            self.quick_sort(data, left, k_idx - 1)
            self.quick_sort(data, k_idx + 1, right)
        return data

    def partation(self, data, low, high):
        left = low
        right = high
        k = data[left]

        while left < right:
            while left < right and data[right] > k:     # not >=  otherwise IndexError: list index out of range
                right -= 1
            while left < right and data[left] <= k:
                left += 1
            if left < right:
                data[left], data[right] = data[right], data[left]
        data[low] = data[right]
        data[right] = k
        return right

实现结果

if __name__ == '__main__':
    test = Sort()
    L = [4,8,5,0,2,7,1,9,3,6]
    res = test.quick_sort(L, 0, len(L)-1)
    res   # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

实现 之 填坑法

图示

python快速排序原理 快速排序法python_python快速排序原理_02


上图中,演示了快速排序的处理过程:

初始状态为一组无序的数组:2、4、5、1、3。

经过以上操作步骤后,完成了第一次的排序,得到新的数组:1、2、5、4、3。

新的数组中,以2为分割点,左边都是比2小的数,右边都是比2大的数。

因为2已经在数组中找到了合适的位置,所以不用再动。

2左边的数组只有一个元素1,所以显然不用再排序,位置也被确定。(注:这种情况时,left指针和right指针显然是重合的。因此在代码中,我们可以通过设置判定条件left必须小于right,如果不满足,则不用排序了)。

而对于2右边的数组5、4、3,设置left指向5,right指向3,开始继续重复图中的一、二、三、四步骤,对新的数组进行排序。

实现

class Sort:
    def quick_sort(self, data, left, right):
        if left < right:
            k_idx = self.partation(data, left, right)
            self.quick_sort(data, left, k_idx - 1)
            self.quick_sort(data, k_idx + 1, right)
        return data

    # 填坑法
    def partation(self, data, low, high):
        left = low
        right = high
        k = data[left]
        while left < right:
            while left < right and data[right] >= k:
                right -= 1
            if  left < right:
                data[left] = data[right]
            while left < right and data[left] <= k:
                left += 1
            if left < right:
                data[right] = data[left]

        data[left] = k
        return left

结果

if __name__ == '__main__':
    test = Sort()
    L = [4,8,5,0,2,7,1,9,3,6]
    res = test.quick_sort(L, 0, len(L)-1)
    res   # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

性能

python快速排序原理 快速排序法python_三数取中法_03

时间复杂度

当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。

而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。

所以,数据越随机分布时,快速排序性能越好;数据越接近有序,快速排序性能越差。

空间复杂度

快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 Nlog2N次的分割处理,所以占用空间也是 O(Nlog2N) 个。

算法稳定性

在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法。