数据结构(七)-二叉堆和堆排序
二叉堆是一种特殊的二叉树,也叫堆数据结构,可以高效的找出最大值和最小值,常被应用于优先队列
二叉堆数据结构
二叉堆数据结构有两个特性:
- 是一颗完全二叉树,树的每一层都有左侧和右侧节点(除了最后一层),并且最后一层叶节点都是左侧节点,称之为结构特性
- 二叉堆不是最小堆就是最大堆。最小堆可以快速导出树的最小值,最大堆可以快速导出树的最大值,称之为堆特性
和二叉搜索树(BST)区别是:二叉搜索树左侧节点比父节点小,右侧节点比父节点大,二叉堆是每个子节点都大于等于父节点(最小堆)或者小于等于父节点(最大堆)
二叉树的数组表示
二叉树可以用链表表示,也可以用数组表示:
对于二叉树节点
以上就是二叉堆的数组表示
最大堆和最小堆
最小堆
1 | |
最大堆
1 | |
获取某个节点的左侧子节点和右侧子节点,父节点
数组形式都是通过index来操作的
- 左侧子节点:2*index+1
- 右侧子节点:2*index+2
- 父节点:index/2
比如我当前的节点index是1(对应的节点key是2),那么我的左侧子节点index就是2*1+1 = 3(也就是节点key为4)
- 最小堆:最小值位于根节点,位于数组第一个位置
- 最大堆:最大值位于根节点,位于数组第一个位置
创建最小堆类
1
2
3
4
5
6
7
8
9
10
11
12
13
14function defaultCompare (a, b) {
if (a === b) {
return Compare.EQUALS;
}
return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
}
// 二叉堆类
class MinHeap {
constructor (compareFn = defaultCompare) {
// 比较存储在数据结构中的值用到的函数
this.compareFn = compareFn
this.heap = []
}
}通过index获取左侧子节点
1
2
3
4// 通过index获取左侧子节点
getLeftIndex(index) {
return 2*index + 1
}通过index获取右侧子节点
1
2
3
4// 通过index获取左侧子节点
getRightIndex(index) {
return 2*index + 2
}通过index获取父节点
1
2
3
4
5
6getParentIndex(index) {
if (index === 0) {
return undefined
}
return Math.floor((index-1)/2)
}向堆中插入值
向堆中插入一个值,如果插入成功,就会返回true,否则返回false1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 当前插入节点的index
siftUp (index) {
// 获取到父节点的index
let parentIndex = this.getParentIndex(index)
// index > 0
// 比较父节点和当前节点大小的值,如果当前节点比父节点小,由这个节点和父节点进行实际的节点交换
while (index > 0 && this.compareFn(this.heap[parentIndex],this.heap[index]) === Compare.BIGGER_THAN) {
// 二叉堆数组, 父节点index,当前插入节点的index
swap(this.heap,parentIndex,index)
// 交换之后,index就是原来的parentIndex
index = parentIndex
// 在获取原来的parentIndex的父index
parentIndex = this.getParentIndex(index)
}
}
const swap = (array, a, b) => [array[a],array[b]] = [array[b],array[a]]
// 测试插入值
const heap = new MinHeap()
heap.insert(2)
heap.insert(3)
heap.insert(4)
heap.insert(5)
heap.insert(1)
console.log(heap) // [1,2,4,5,3]
从堆中找到最大值或者最小值
1
2
3
4
5
6
7
8
9
10// 获取堆长度
size() {
return this.heap.length
}
isEmpty () {
return this.size() === 0
}
findMin() {
return this.isEmpty() ? undefined : this.heap[0]
}移除最小堆中的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35// 移除堆中的最小值或者最大值
// 直接移除掉第一个元素,然后将末尾的元素赋值到第一个,在不断进行遍历替换
extract() {
if (this.isEmpty()) {
return undefined
}
if (this.size() === 1) {
return this.heap.shift()
}
const removedValue = this.heap.shift()
// 和siftUp操作相反
this.siftDown(0)
return removedValue
}
// 向下移动
siftDown(index) {
// index为0
let element = index
// index为根节点 获取左侧第一个子节点索引
const left = this.getLeftIndex(index)
// index为根节点 获取右侧第一个子节点索引
const right = this.getRightIndex(index)
// 获取当前节点的长度length
const size = this.size()
if (left < size && this.compareFn(this.head[element], this.heap[left] > Compare.BIGGER_THAN)) {
element = left
}
if (right < size && this.compareFn(this.head[element], this.heap[right] > Compare.BIGGER_THAN)) {
element = right
}
if (element !== index) {
swap(this.heap, index, element)
this.siftDown(element)
}
}最大堆
和最小堆代码相同,但是需要修改一下比较大小的大于换成小于1
2
3
4
5
6
7
8
9
10
11// 最大堆
class MaxHeap extends MinHeap {
constructor(compareFn = defaultCompare) {
super(compareFn)
this.compareFn = reverseCompare(compareFn)
}
}
// 利用函数柯里化
function reverseCompare(compareFn) {
return (a, b) => compareFn(b, a)
}
本文标题:数据结构(七)-二叉堆和堆排序
文章作者:Niuhk
发布时间:2022-01-28
最后更新:2022-01-28
原始链接:https://www.niuhk.cn/2022/01/28/数据结构(七)-二叉堆和堆排序/
版权声明:转载请注明出处!
分享