荷兰国旗与快速排序

本文详细解析了荷兰国旗问题的解决策略,包括初始化边界、比较与交换元素的过程,以及如何通过递归实现快速排序算法。同时,对比了经典快排与随机快排的优缺点,强调了随机快排在数据分布不均匀情况下的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

荷兰国旗问题

荷兰国旗问题:给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。

以arr = [3,8,9,2,5,5],num = 5为例。

解决荷兰国旗问题的思路

初始化小于边界less = -1,大于边界more = len(arr) = 6,当前比较的位置cur = 0。

  • 如果当前位置上的数小于 num,交换当前位置上的数与边界less后一个元素,扩大小于num的范围,less += 1,cur += 1;
  • 如果当前位置上的数大于 num,交换当前位置上的数与边界more前一个元素,扩大大于num的范围,more -=1, cur 不变;
  • 如果当前位置上的数等于num,less和more均不变,cur += 1。

当cur = more时,停止比较,返回。

第一步:

初始化小于边界less = -1,大于边界more = len(arr) = 6,当前比较的位置cur = 0。

在这里插入图片描述

第二步:比较cur = 0位置上的数与num

arr[cur] = 3,arr[cur] < num,所以,交换当前位置上的数与边界less后一个元素(此处,两者为同一元素3,可不做交换),less += 1, cur += 1。得到:less = 0,cur = 1,more = 6。

在这里插入图片描述

第三步:比较cur = 1位置上的数与num

arr[cur] = 8, arr[cur] > num,所以,交换当前位置上的数与边界more前一个元素,more -= 1,cur不变。得到:less = 0,cur = 1,more = 5。

在这里插入图片描述

第四步:比较cur = 1位置上的数与num

arr[cur] = 5, arr[cur] = num, 所以,less不变,more不变,cur += 1。得到:less = 0,cur = 2,more = 5。

在这里插入图片描述

第五步:比较cur = 2位置上的数与num

arr[cur] = 9, arr[cur] > num, 所以,交换当前位置上的数与边界more前一个元素,less不变,more -= 1,cur不变。得到:less = 0,cur = 2,more = 4。

在这里插入图片描述

第六步:比较cur = 2位置上的数与num

arr[cur] = 5, arr[cur] = num, 所以,less不变,more不变,cur += 1。得到:less = 0,cur = 3,more = 4。

在这里插入图片描述

第七步:比较cur = 3位置上的数与num

arr[cur] = 2, arr[cur] < num, 所以,交换当前位置上的数与边界less后一个元素,less += 1,cur += 1,more不变。得到:less = 1,cur = 4,more = 4。

在这里插入图片描述

第八步:

此时,cur = 4 = more,停止比较,返回数组。实现了小于num的在左边,大于num的在右边,等于num的在中间。

代码实现

def partition(arr, l, r, num):
    less = l - 1 # 小于边界
    more = r + 1 # 大于边界
    cur = less + 1 # 当前比较位置
    while cur < more:
        if arr[cur] < num:
            arr[less + 1], arr[cur] = arr[cur], arr[less + 1]
            less += 1
            cur += 1
        elif arr[cur] > num:
            arr[more - 1], arr[cur] = arr[cur], arr[more - 1]
            more -= 1
        else:
            cur += 1
    return arr

if __name__ == '__main__':
    a = [3, 8, 9, 2, 5, 5]
    print(partition(a, 0, len(a) - 1, 5))

 

经典快排

经典快排的思路

取数组最后一个元素作为划分值,将小于划分值的数放在左边,大于划分值的数放在右边,等于划分值的数放在中间。然后,对左右两部分继续进行上述划分。直到仅剩一个元素为止。

仍以数组arr = [3, 8, 9, 2, 5, 5]为例:

第一步:

取数组最后一个元素做划分值,即num = 5。将小于5的放在左边,大于5的放在右边,等于5的放中间。属于arr=[3,8,9,2,5,5],num = 5的荷兰国旗问题。得到小于边界less = 1,大于边界more = 4,如下图:

在这里插入图片描述

第二步:

对于0至less部分,取其最后一个元素做划分值;相当于是arr = [3,2],num = 2的荷兰国旗问题。得到小于边界less = -1,大于边界more = 1。

对于more至 len([3,2,5,5,9,8]) 部分,仍取其最后一个元素做划分值;相当于是arr = [9,8],num = 8的荷兰国旗问题。可得小于边界less = 3,大于边界more = 5。如下图:

在这里插入图片描述

第三步:

对于左边数组[2,3],其数组边界为left = 0,right = 1

less = -1,对于left到less部分,left大于less,没有元素,返回;

more = 1,对于more到len([2,3]) = 2,仅有一个元素,返回;

对于右边数组[8,9],其数组边界为left = 4,right = 5

less = 3,对于left到less部分,left大于less,没有元素,返回;

more = 5,对于more到 len([2,3,5,5,8,9]) = 6, 仅有一个元素,返回。

排序完成!

代码实现

def quick_sort(arr, l, r, num):
    if l < r:  # 当满足这个条件 一直做下去
        less, more = partition(arr, l, r, num)
        quick_sort(arr, l, less, arr[less])
        quick_sort(arr, more, r, arr[r])
    return arr

def partition(arr, l, r, num):
    less = l - 1
    more = r + 1
    cur = less + 1
    while cur < more:
        if arr[cur] < num:
            arr[less + 1], arr[cur] = arr[cur], arr[less + 1]
            less += 1
            cur += 1
        elif arr[cur] > num:
            arr[more - 1], arr[cur] = arr[cur], arr[more - 1]
            more -= 1
        else:
            cur += 1
    return less, more

if __name__ == '__main__':
    arr = [3, 8, 9, 2, 5, 5]
    print(quick_sort(arr, 0, len(arr) - 1, arr[-1]))

经典快排存在的缺陷

每次都使用数组最后一个元素做划分值,复杂度跟数据状况有很大的关系。

以数组 [1,2,3,4,5,6]为例,每次只排好了一个数,时间复杂度是O(n^2)。

于是,有了随机快排。

随机快排

随机快排的思路

随机选取数组中的数作为划分值,将小于划分值的数放在左边,大于划分值的数放在右边,等于划分值的数放在中间。然后,对左右两部分继续进行上述划分。直到仅剩一个元素为止。使用随机,完美地避开了数据状况问题。

代码实现

仅需在经典快排的基础上,添加一个随机函数即可。

import random, math

def quick_sort(arr, l, r, num):
    if l < r: 
        # 随机选取l到r之间的数,与最后一个位置上的数进行交换
        # 舍弃浮点数后面的小数位,并取整
        random_pos = l + int(math.floor(random.random() * (r - l + 1)))  
        arr[r],arr[random_pos] = arr[random_pos],arr[r]
        less, more = partition(arr, l, r, num)
        quick_sort(arr, l, less, arr[less])
        quick_sort(arr, more, r, arr[r])
    return arr


def partition(arr, l, r, num):
    less = l - 1
    more = r + 1
    cur = less + 1
    while cur < more:
        if arr[cur] < num:
            arr[less + 1], arr[cur] = arr[cur], arr[less + 1]
            less += 1
            cur += 1
        elif arr[cur] > num:
            arr[more - 1], arr[cur] = arr[cur], arr[more - 1]
            more -= 1
        else:
            cur += 1
    return less, more


if __name__ == '__main__':
    arr = [3, 8, 9, 2, 5, 5]
    print(quick_sort(arr, 0, len(arr) - 1, arr[-1]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值