【算法】排序算法(快速排序) - Partition - 联系到堆 - 堆数据结构基础 - 个人算法要点简记



1 Partition

要点:

  • pivot
  • 返回值:k,x 数组的 k 位置已经是正确的顺序。
  • 返回值是“随机”的。
  • pivot 值在“进一步优化”的角度来说很重要,尽可能要选择中位数。
  • 因为不知道中位数等,pivot 在无其它调整/优化的基本 Partition 算法中本质是随机的。

Python 语言实现 partition:

def partition(arr, left, right):
    if left >= right:
        return

    _l = left
    _r = right
    pivot = arr[left]
    while True:
        while arr[_l] <= pivot:
            _l += 1
            if _l == right:
                break
        while arr[_r] >= pivot:
            _r -= 1
            if _r == left:
                break
        if _l >= _r:
            break
        arr[_l], arr[_r] = arr[_r], arr[_l]

    arr[left], arr[_r] = arr[_r], arr[left]
    return _r

这边的写法是基于 《算法(java)》中的实现。不同的书籍等对与 partition 的实现细节上可能略有不同,比如判断边界,退出循环的写法等,但是程序逻辑上都是一样的。

参考 stackoverflow.com 🔗 Quicksort with Python 有更简洁的写法。

def partition(array, begin, end):
    pivot = begin
    for i in xrange(begin+1, end+1):
        if array[i] <= array[begin]:
            pivot += 1
            array[i], array[pivot] = array[pivot], array[i]
    array[pivot], array[begin] = array[begin], array[pivot]
    return pivot

经过测试是正确的!,可以 copy 直接使用!



2 应用

2.1 Quick Sort

要点:partition 的 k 位置是排好序的,k 位置一分为二,分别调用 quick sort 继续排序(递归)。

使用递归可以很简单地基于 partition 函数实现快速排序(不过对于非常长的数组,会存在递归深度过长的情况)
递归实现的快速排序:

def _quick_sort(arr, left, right) -> None:
    if left >= right:
        return None

    middle = partition(arr, left, right)
    _quick_sort(arr, left, middle - 1)
    _quick_sort(arr, middle + 1, right)
    return None

def quicksort(arr) -> None:
    # 可以考虑调用 build-in function suffle 函数,随机化数组顺序。
    _quick_sort(arr, 0, len(arr) - 1)

不过 Python 内置的 sorted 函数很好用,所以如果是给定的确定列表做排序,自然不会自己去实现。
相信会用到自己去写排序算法的时候,一般都是变体的应用场景。

快速算法算法的复杂度: 1.39 N l g N 1.39NlgN 1.39NlgN

n/a



2.2 第(前) K 大(小)的数

2.2.1 Partition 解法

要点:
将 partition 的返回值和 k 比较,直到等于 k 为止。

注意返回值 和 k 不同,下一步要选择合适的范围继续调用 Partition

复杂度: O ( n ) O(n) O(n)

实现:

2020/07/13
因为在做 leetcode,遇到一道题,需要找到“前K大的数”,所以使用了 partition 函数。
并且做了实现,于是就在这篇 blog 上更新具体的实现如下。

def find_k_minimal_numbers(array, k):
    '''in place'''
    p = -1
    L = 0
    R = len(array) - 1
    while True:
        p = partition(array, L, R)
        if p == k - 1:
            return
        else:
            if p < k - 1:
                L = p + 1
            else:
                R = p - 1

本来找到前 K 个大的数想要用堆实现,但是想来堆的实现相对于 partition 来说肯定是要复杂的。所以在数组不是非常大的情况下,partition 解法应该是优先选择。



2.2.2 大数据集 - 堆解法

要点:

  • 第(前)K 大 - 最小堆;插入新的较大值,删除(挤出)最小值
  • 第(前)K 小 - 最大堆;插入新的较小值,删除(挤出)最大值

复杂度: O ( n l o g k ) O(nlogk) O(nlogk)



3 关于堆

要点:

  • 二叉树
  • 完全二叉树性质
  • 堆性质
  • 显式(链表)表示方式和隐式(数组)表示方式

完全二叉树性质在隐式(数组)表示方式中的节点定位应用。


3.1 实现

要点:

  • 结构实现

    使用数组保存(节点)值。索引即节点。
    使用数组的实现,需要对数组索引 0 位置使用一个占位符,因为需要从 1 开始索引。
    维护一个“真实”堆的值的大小,操作函数中对此有很多需要。

  • 操作函数

    • 插入

      在数组末尾添加元素,保证完全二叉树性质;
      需要一个向上交换函数,交换新的末尾元素,保证堆性质。

    • 删除(最大/小 - 顶点)

      取顶点值,数组末尾与顶点交换,删除数组末尾元素(即原来的顶点),更新维护的长度值;
      需要一个向下交换函数,交换前面的交换到顶点的原末尾元素,保证堆性质;
      因为堆中无左右孩子大小排序一说,所以需要另外一个辅助函数,取左右还是中的最小顶点(最小堆)或是最大顶点(最大堆)返回给调用方 – 向下交换函数。

    • O ( n ) O(n) O(n) 构建堆

      Python 中考虑使用 @classmethod


3.2 应用

3.2.1 一、 堆排序 - O ( n l o g n ) O(nlogn) O(nlogn)

因为构建堆 - O ( n ) O(n) O(n) 复杂度就能得到数组最小值(正序排序,最小堆)
+
n 次 * “删除”最小元素(正序排序)- 顶点 ( l o g n ) (logn) (logn) O ( n l o g n ) O(nlogn) O(nlogn)
||
\/

O ( n ) + O ( n l o g n ) O(n) + O(nlogn) O(n)+O(nlogn) O ( n l o g n ) O(nlogn) O(nlogn)


3.2.2 二、上文的找“第(前) K 大(小)的数”


Reference



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 JavaScript 编写的记忆游戏(附源代码)   项目:JavaScript 记忆游戏(附源代码) 记忆检查游戏是一个使用 HTML5、CSS 和 JavaScript 开发的简单项目。这个游戏是关于测试你的短期 记忆技能。玩这个游戏 时,一系列图像会出现在一个盒子形状的区域中 。玩家必须找到两个相同的图像并单击它们以使它们消失。 如何运行游戏? 记忆游戏项目仅包含 HTML、CSS 和 JavaScript。谈到此游戏的功能,用户必须单击两个相同的图像才能使它们消失。 点击卡片或按下键盘键,通过 2 乘 2 旋转来重建鸟儿对,并发现隐藏在下面的图像! 如果翻开的牌面相同(一对),您就赢了,并且该对牌将从游戏中消失! 否则,卡片会自动翻面朝下,您需要重新尝试! 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox, 以获得更好、更优化的游戏体验。要玩游戏,首先,通过单击 memorygame-index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值