吃透排序算法之划分排序

吃透排序算法之划分排序

排序算法不仅仅是无序到有序, 其中涉及了数组的遍历处理, 划分的模板运用, 甚至其中还设计到了数组到树的堆化处理. 可以说吃透了排序算法, 可以成为一个合格的算法初学者了.

本系列文章带领读者吃透排序算法, 掌握数组的处理方式, partition模板, 数组的二叉树形式并进行堆化处理.

吃透排序算法之划分排序为本系列的划分排序介绍, 主要介绍几种高级的排序, 也是默认在各个语言内置排序中的算法, 本文主要涉及:

  • 快速排序
  • 归并排序

快速排序

快速排序顾名思义, 是一种时间复杂度和空间复杂度比较优秀的算法, 也因此可以被选入各个语言默认的排序算法. 原理类似于划分, 每次使得数组基准位置前面都小于基准数, 后面大于基准数.

这也是第一次接触划分和partition, 一种比较好的去处理数组的方式, 通过控制lr, 在了l<r时进行划分.

def partition(l, r): # partition模板
    if not l < r:
        return
    # m = 
    partition(l, m)
    partition(m+1, r)

快速排序基准数的位置需要到算法完成才知道, 因此更多的处理就是在计算m. 选定l位置为基准数, 数组rl找到一个小于基准数的位置和基准数交换, 之后从lr找到一个大于基准数的位置和之前小于基准数的位置交换.

 nums = [1, 3, 2, 5, 4, 6]


def partition(l, r):
    if not l < r:
        return
    b = nums[l]
    i, j = l, r
    while i < j:
        while i < j and nums[j] > b:
            j -= 1
        if i < j:
            nums[i] = nums[j]
        while i < j and nums[i] < b:
            i += 1
        if i < j:
            nums[j] = nums[i]
    nums[i] = b
    m = i
    partition(l, m)
    partition(m+1, r)


partition(0, len(nums)-1)
print(nums)

归并排序

归并排序和快速排序都属于划分排序, 如果说快速排序在于划分, 归并排序就是在于合并了. 按照之前的划分算法, 归并的划分并不难. 归并排序将数组分割成两部分, 使两部分均有序, 再将两部分回去.

def partition(l, r):
    if not l < r:
        return
    m = int((l+r)/2)
    partition(l, m)
    partition(m+1, r)
    # 如何合并

引入一个思考, 在不借助额外空间的情况下, 如何移动数组. 举个例子[3,4,5,1,2]如何移动成为[1,2,3,4,5]? 一个比较好的方式就是反转反转反转. 数组前三个和后两个交换, 可以先反转为5,4,3, 再反转2,1, 之后整体反转为[1,2,3,4,5]. 反转实现利用了双指针的技巧, 比较好想.

def reverse(p, q):
    while p < q:
        nums[p], nums[q] = nums[q], nums[p]
        p += 1
        q -= 1
reverse(i, k)
reverse(k+1, j)
reverse(i, j)

接下来去看看归并什么位置需要反转即可, l找到一个比m+1大的, r也移动到比l大的位置. 此时就是期望的反转位置, 调用反转即可.

nums = [1, 3, 2, 5, 4, 6]


def partition(l, r):
    if not l < r:
        return
    m = int((l+r)/2)
    partition(l, m)
    partition(m+1, r)
    i, j = l, m+1
    while i < j <= r:
        while i < j <= r and nums[i] < nums[j]:
            i += 1
        k = j
        while i < j <= r and nums[j] < nums[i]:
            j += 1

        def reverse(p, q): #双指针反转
            while p < q:
                nums[p], nums[q] = nums[q], nums[p]
                p += 1
                q -= 1
        reverse(i, k-1)
        reverse(k, j-1)
        reverse(i, j-1)
        i += (j-1)-k+1


partition(0, len(nums)-1)
print(nums)


小结

本文介绍了快速排序的实现, 了解了归并排序的原理和实现, 引入了数组整体交换的问题, 并提出可以通过三次反转实现. 快速排序和归并排序同属于划分排序, 但侧重点不同, 快速排序侧重划分, 归并排序侧重合并.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值