定义与原理
二叉堆是一种特殊的堆。具有如下的特性:
- 具有完全二叉树的特性
- 堆中的任何一个父节点的值都大于等于它左右孩子节点的值,或者都小于等于它左右孩子节点的值
二叉堆分为两类:
- 最大堆
父节点的值大于等于
左右孩子节点的值
- 最小堆
父节点的值小于等于左右孩子节点的值
堆顶
:二叉堆的根节.
二叉堆的三个主要操作:
- 插入一个节点。
- 删除一个节点。
- 构建一个二叉堆。
在二叉堆这种结构中,对于删除一个节点,我们一般删的是根节点
代码实现
二叉树一般是采用链表的方式来实现的,但二叉堆我们是采用数组的方式来存储的
如果知道了一个节点的位置,如何知道一个节点的左右孩子节点的位置呢?
这其实不难,根据完全二叉树的特点,假如一个节点的下标为n,则可以求得它左孩子的下标为:2n+1
;右孩子下标为:2n+2
。
//Author:Shawn
//Email:stepfencurryxiao@gmail.com
/*
* 1
* / \
* 2 3
* / \ / \
* 5 4 6 7
* / \
* 8 9
*
* Array:[1,2,3,5,4,6,7,8,9]
*
* leftchild : 2n + 1
* rightcgild : 2n + 2
*/
List upAdjust(List arr,int length){
//标记插入的节点
var child = length - 1;
//其父节点
int parent = ((child - 1) / 2).toInt();
//把插入的节点临时保存起来
int temp = arr[child];
//进行上浮
while(child > 0 && temp < arr[parent]){
//当temp找到正确的位置之后,我们再把temp的值赋给这个节点
arr[child] = arr[parent];
child = parent;
parent = ((child - 1) / 2).toInt();
}
arr[child] = temp;
return arr;
}
/**
* 下沉操作,执行删除操作相当于把最后
* * 一个元素赋给根元素之后,然后对根元素执行下沉操作
* @param arr
* @param parent 要下沉元素的下标
* @param length 数组长度
*/
List downAdjust(List arr,int parent,int length){
//保存要下沉的元素
int temp = arr[parent];
//定位左孩子节点位置
int child = 2 * parent + 1;
//开始下沉
while (child < length) {
//如果右孩子节点比左孩子小,则定位到右孩子
if (child + 1 < length && arr[child] > arr[child + 1]) {
child++;
}
//如果父节点比孩子节点小或等于,则下沉结束
if (temp <= arr[child])
break;
//单向赋值
arr[parent] = arr[child];
parent = child;
child = 2 * parent + 1;
}
arr[parent] = temp;
return arr;
}
List buildHead(List arr,int length) {
//从最后一个非叶子节点开始下沉
for (int i = ((length - 2) / 2).toInt(); i >= 0; i--) {
arr = downAdjust(arr, i, length);
}
return arr;
}
void main(){
List arr = [1,3,0,5,4,6,7,8,9];
List BinaryHeap = buildHead(arr,arr.length);
print(BinaryHeap);
}
运行结果:
[0, 3, 1, 5, 4, 6, 7, 8, 9]