二叉堆(以最小堆为例),其具有结构性质和堆序性质
结构性质: 堆是一棵完全的二叉树,一颗高为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"); } }
结果:
好饿啊。。。。。。。。。。。。。。
时间: 2024-10-07 04:00:08