结构性和堆序性
堆:堆是一棵被完全填满的二叉树,只有底层从左到右填入,可能不满。
一棵高为h的二叉树,节点个数为2^h到2^(h+1);
用一个数组存储该完全二叉树,数组【0】空闲,从【1】开始存储该堆,则位置i上的节点A,其左儿子在位置(2i)处,右儿子在位置(2i+1)处;对应一节点A的父节点位置为【i/2】下取整。
数组实现的堆:
数组【0】空闲,从【1】开始存储该堆,则位置i上的节点A,其左儿子在位置(2i)处,右儿子在位置(2i+1)处;对应一节点A的父节点位置为【i/2】下取整。
链表实现的堆:
类似于二叉树,每个节点至少需要两个指针,指向他的左右子节点。
利用这种结点结构所得的二叉树存储结构称之为二叉链表。在二叉链表中,如果想找到某个结点的双亲,需要从根节点开始遍历,所以有时为了便于找到结点的双亲,还可以在结点结构中增加一个指向其双亲结点的指针域,相应的二叉树存储结构称之为三叉链表。
堆元素插入——上滤
对元素删除——下滤
上滤和下滤避免了为最后元素寻找合适位置时的多次交换赋值,一个元素上虑d层,交换赋值达到3d次,而我们的方法仅需要d+1次。
上滤:新添加一个元素A,首先虚拟锁定hole——【hole(n)】,若A大于[n/2],则将【n/2】元素复制到【n】,更新n,继续迭代操作,直到A<=【n/2】时,将A放入【n】位置。
上滤代码:
public void insert(AnyType x){
if(currentSize==array.length-1){
enlargeArray(array.length*2+1);
}
//上滤
int hole=++currentSize;
for(;hole>1&&x.compareTo(array[hole/2])<0;hole/=2){
array[hole]=array[hole/2];
}
array[hole]=x;
}
下滤代码:
在deleteMin中,调用下滤方法,出入的hole应该为1,即根节点的位置
前一步操作:array[1]=array[currentSize--];保证删除最小元素后,将最后位置的元素首先复制到根位置,保证堆的结构性,然后调用percolateDown(),调整保证堆序性。
private void percolateDown(int hole){
int child;
AnyType tmp=array[hole];
for(;hole*2<currentSize;hole=child){
//注意这里,保证有两个子节点,就算只有一个子节点(child+1-->null)
//找到两个子节点中的较小者,将其上移,即hole向下移动一层
if(child!=currentSize&&array[child+1].compareTp(array[child])<0){
child++;
}
if(array[child].compareTo(tmp)<0){
array[hole]=array[child]
}else
break;
}
array[hole]=tmp;
}