堆
说到堆就必须要说二叉树,二叉树指每个节点最多只能包含两个子节点的树。二叉树常用的实现为二叉搜索树(BinarySearchTree)和二叉堆(BinaryHeap)
这里不再对树的概念进行赘述,有需求的自行google,二叉堆其实对应着一棵完全二叉树,最后一层除外。因此使得一个堆可以利用数组来存储,二叉堆又分为大根堆和小根堆,下图展示了一个大根堆与数组的对应。
因此可以很简单的得到堆节点所对应的数组。 :banana:
- 父节点parent = index / 2
- 左节点left = index * 2
- 右节点right = index * 2 + 1
堆排序
堆排序就是把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束。在堆中定义以下几种操作:
- 最大堆调整(Max-Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。
- 创建最大堆(Build-Max-Heap):将堆所有数据重新排序,使其成为最大堆。
- 堆排序(Heap-Sort):移除位在第一个数据的根节点,并做最大堆调整的递归运算。
通俗的解释就是: 最大堆调整(Max-Heapify)其实就是一次 <下沉> 的过程,创建最大堆(Build-Max-Heap)就是 <循环> 每个节点进行 最大堆调整,堆排序(Heap-Sort)就是每次 创建完最大堆 之后需要将最大元素 <分离>。
一句话概括:循环树的每一个节点进行下沉,然后分离,继续循环。 :tomato:
下图展示了一次下沉的过程:
优先队列
普通的队列满足先进先出,而优先队列满足每次出队列的都是优先级最高的元素。 :strawberry:
常见的优先队列有三种实现方式:
- 有序数组(add时添加到排序的位置,poll时候移除队尾元素)
- 无序数组(add时直接添加到队尾,poll时查找优先元素)
- 二叉堆(add时上浮,poll时下沉)
优先队列与堆排序的关系
因为优先队列每次poll只需要最大优先级的元素,所以不需要维持整棵二叉堆的有序,只需要维持根节点满足最大优先级即可。所以只需要对根节点进行一次堆排序的最大堆调整(Max-Heapify)即可。
Java优先队列源码解析
1 | 复制代码 |
本文转载自: 掘金