在生产中应用广泛的排序算法
在生产系统中经常会有这么一种场景,就是在生产系统中跑一些批量任务,会与正常的业务使用相同的消息队列,为了不对用户操作造成影响需要对消息区分等级,客户端优先消费消息队列中权重最高的消息,从而保证正常业务的运行,这也就是优先队列。
优先队列的特点:能保证每次取出的元素都是队列中优先级别最高的。优先级别可以是自定义的, 例如, 数据的数值越大, 优先级越高, 或者数据的值越小, 优先级越高,通常采用堆来实现。
堆看上去就是树,区别在哪呢??
堆是用数组实现的二叉树,所以它没有使用父指针或者子指针。
节点顺序不同
在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。
内存占用不同
普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额外的内存。堆仅仅使用一个数组来存储数据,且不使用指针。
平衡不同
二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到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]))
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- python里运行shell命令或cmd命令
- 玩转 PhpStorm 系列(四):快捷键篇
- HDFS工作机制和原理
- 通过 PHP Mysqli 扩展与数据库交互
- python 中的元类详解
- 我扒了半天源码,终于找到了Oauth2自定义处理结果的最佳方案!
- python 解决多核处理器算力浪费的现象
- python实现单例模式的5种方法
- java序列化和序列化ID的作用
- python函数式编程
- 让Vim打造成强大的IDE,附_vimrc的配置和使用
- python 中面向切面编程AOP和装饰器
- HashMap&ConcurrentHashMap&HashTable
- python中的垃圾回收机制
- python中值传递还是引用传递?