标签:
二叉堆(以最小堆为例),其具有结构性质和堆序性质
结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N
而且该结构可以很容易的使用数组来表示:对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在2i+1,其父节点在[x/2]处
堆序性质:在一个堆中,对于每一个节点X,X的父亲中的关键字小于或等于X中的关键字
也就是说:最小元总可以在根处找到
主要的操作为插入和删除:
以数组存储为例,算法在代码中体现:
/**
* 向堆中插入元素x,
* 利用堆的性质,在一个堆中,对于每一个节点X,X的父亲中的关键字都小于或者等于X中的关键字,
* ps根节点除外(根节点没有父节点),时间复杂度为logN
* step1:如果堆没有满,在完全二叉树的下一个位置插入一个空穴
* step2:判断空穴是否存在父节点,如果不存在,直接插入;否则,step3;
* step3:(x.value>=[x/2].value)?step4:step5;
* step4:将X直接放在该空穴,return
* step5:将父节点的值移入空穴中,空穴就朝着根的方向上前进,回到step2;
* @param x
*/
public void insert(Comparable x){
if(cursize == array.length-1){
//堆已经满了,需要重新调整
rebuild();
}
if(cursize==0){
//没有父节点
array[1] = x;
cursize++;
}else{
int temp = ++cursize;
while(temp>1 && x.compareTo(array[temp/2])<0){
//父节点下移
array[temp] =array[temp/2];
temp/=2;
}
//空穴插入
array[temp] = x;
}
}
删除操作:
/**
* 删除堆中的最小元素并返回,方式与插入向反,时间复杂度为logN
* step1:将根节点出视为空穴X
* step2:if(空穴X的左右子树都存在) step3;else if(空穴只存在左子树) step4 ;else step5
* step3:if(空穴的X的左子树2X>X的右子树2X+1) 空穴<-->右子树;else 空穴<-->左子树;finally 继续step2
* step4:空穴和左子树交换,空穴已就位,且满足完全二叉树的要求
* step5:空穴和最后一个元素交换位置
* @return
*/
public Comparable deleteMin(){
if(isEmpty())
return null;
Comparable min = array[1];
int temp = 1;
while(2*temp<=cursize){
if(2*temp+1<=cursize){
//左右子树都存在
if(array[2*temp].compareTo(array[2*temp+1])>0){
array[temp] = array[2*temp+1];
temp = 2*temp+1;
}else{
array[temp] = array[2*temp];
temp = 2*temp;
}
}else{
//只存在左子树
array[temp] = array[2*temp];
temp = 2*temp;
}
}
array[temp] = array[cursize--];
return min;
}
测试代码:
@Test
public void test() {
BinaryHeap heap = new BinaryHeap();
for(int i = 19;i>1;i--){
heap.insert(i);
// heap.printHeap();
}
while(!heap.isEmpty()){
System.out.print(heap.deleteMin()+"\t");
}
}
结果:
好饿啊。。。。。。。。。。。。。。
标签:
原文地址:http://www.cnblogs.com/kakaxisir/p/4316693.html