在生产中应用广泛的排序算法

时间:2022-07-22
本文章向大家介绍在生产中应用广泛的排序算法,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

在生产系统中经常会有这么一种场景,就是在生产系统中跑一些批量任务,会与正常的业务使用相同的消息队列,为了不对用户操作造成影响需要对消息区分等级,客户端优先消费消息队列中权重最高的消息,从而保证正常业务的运行,这也就是优先队列。

优先队列的特点:能保证每次取出的元素都是队列中优先级别最高的。优先级别可以是自定义的, 例如, 数据的数值越大, 优先级越高, 或者数据的值越小, 优先级越高,通常采用堆来实现。

堆看上去就是树,区别在哪呢??

堆是用数组实现的二叉树,所以它没有使用父指针或者子指针。

节点顺序不同

在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用不同

普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额外的内存。堆仅仅使用一个数组来存储数据,且不使用指针。

平衡不同

二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

搜索不同

在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。

堆的应用堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。

堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点,根结点最大叫大根堆,根结点最小的叫小根堆。

  • 时间复杂度O(N*logN)
  • 空间复杂度O(1)
  • 不稳定排序:比如一个数组222,我们建立大根堆时,堆顶元素会换到最后的位置上去,导致第一个2排序后跑到了最后面,破坏了数据的稳定性。

首先是把数组建中的n个数建成一个大小为n的大根堆,堆顶元素数树的最大值,将堆顶元素与堆的最后一个元素进行位置互换,然后把最大值脱离出堆结构,放在数组的最后位置,作为数组的有序部分;然后对n-1的堆进行位置调整,把最大值放在堆顶;再重复堆顶数据与堆的最后一位进行位置交换,存入有效部分,当堆的大小为1的时候,数据就变得有序了。

Python实现大根堆排序

# 堆排序
def heapify(arr, n, i):
    # 根节点序号
    largest = i
    # 计算子根节点序号
    l = 2 * i + 1  # left = 2*i + 1
    r = 2 * i + 2  # right = 2*i + 2
    # 判断左子树是否存在
    if l < n and arr[i] < arr[l]:
        largest = l

    # 判断右子树是否存在
    if r < n and arr[largest] < arr[r]:
        largest = r

    # 最大的节点序号 不等于 根节点的序号时,
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]  # 交换
        heapify(arr, n, largest)


def heapSort(arr):
    n = len(arr)

    # Build a maxheap.
    # 二叉树层遍历的 生产二叉树
    # 构建大堆
    for i in range(n, -1, -1):
        heapify(arr, n, i)
        print(arr, i)
        # 一个个交换元素
    for i in range(n - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]  # 交换
        heapify(arr, i, 0)
    return arr


if __name__ == "__main__":
    print(heapSort([45, 32, 8, 33, 12, 22, 19, 97]))