①、它是完全二叉树,除了树的最后一层节点不需要是满的,其它的每一层从左到右都是满的。注意下面两种情况,第二种最后一层从左到右中间有断隔,那么也是不完全二叉树。
②、它通常用数组来实现。
这种用数组实现的二叉树,假设节点的索引值为index,那么:
节点的左子节点是 2*index+1,
节点的右子节点是 2*index+2,
节点的父节点是 (index-1)/2。
③、堆中的每一个节点的关键字都大于(或等于)这个节点的子节点的关键字。
这里要注意堆和前面说的二叉搜索树的区别,二叉搜索树中所有节点的左子节点关键字都小于右子节点关键字,在二叉搜索树中通过一个简单的算法就可以按序遍历节点。但是在堆中,按序遍历节点是很困难的,如上图所示,堆只有沿着从根节点到叶子节点的每一条路径是降序排列的,指定节点的左边节点或者右边节点,以及上层节点或者下层节点由于不在同一条路径上,他们的关键字可能比指定节点大或者小。所以相对于二叉搜索树,堆是弱序的。
package alorgrithm;
public class HeapNode {
private int iData;
public HeapNode(int key){
iData=key;
}
public int getKey(){
return iData;
}
public void setKey(int key){
iData=key;
}
}
package alorgrithm;
/***
* 数组表示堆:若节点的索引是index
* 节点的左节点:2*index+1
* 节点的右节点:2*index+2
* 节点的父节点:(index-1)/2
* 堆中每一个节点的关键字都大于或者等于这个节点子节点的关键字
* 堆遍历困难,每一条路径 ,只有从根节点到叶子节点是降序
*
*适合快速移除最大节点的操作以及快速插入新的节点的操作。
*
* 移除:删除关键字最大或者最小也就是根节点
* 根节点在数组中的索引值总是0既maxNode=heapArray[0];
* 移除后根节点空位填上:
* 1.移走根
* 2.把最后一个结点移动到根的位置上。
* 3.一直向下筛选这个节点直到在一个大于它的节点之下,小于它的节点之上。
* heapArray[0]=heapArray[N-1];
*N--
*向下筛选需要检查哪一个子节点更大,然后目标节点和较大的子节点交换位置。
* 如果目标节点和较小的交换会违背堆的条件。
* 插入:
* 插入是向上筛选,初始时插入到数组最后一个空着的单元。
* 数组容量大小增1.
* heapArray[N]=newNode;
* N++;
* 向上筛选直到在一个大于它的节点之下,在一个小于它的节点之上。
*向上筛选的算法比向下刷选的算法相对简单
* 使用临时存储区减少复制次数。
*/
public class Heap {
private int maxSize;
private int currentSize;
private HeapNode heapArray[];
public Heap(int maxSize)
{
this.maxSize=maxSize;
heapArray=new HeapNode[maxSize];
}
/***
* 移除:
* 1.最后一个元素放入根节点
* 2.向下筛选
* 3.
* @return 返回删除结点
*/
public HeapNode remove(){
HeapNode root=heapArray[0];
heapArray[0]=heapArray[--currentSize];
//currentSize--;
trickDown(0);
return root;
}
/**
* 1.先判断是否满,满则退出。
* 2.插入到最后位置
* 3.调用trickleUp(int index ) 向上筛选
* @return
*/
public boolean insert(int iData){
if(currentSize==maxSize){
return false ;
}
HeapNode newNode =new HeapNode(iData);
heapArray[currentSize]=newNode;
trickUp(currentSize++);
return true;
}
/***
* 临时存储区 HeapNode bottpm
* @param index
*/
public void trickUp(int index){
HeapNode bottoom = heapArray[index];
int parent = (index - 1) / 2;
while (index > 0 && (heapArray[parent].getKey()<bottoom.getKey())) {
heapArray[index] = heapArray[parent];
index = parent;
parent = (parent - 1) / 2;
}
heapArray[index] = bottoom;
}
/***
* 1.
* @param index 向下筛选
*/
public void trickDown(int index){
HeapNode top= heapArray[index];//save root
int lagerChild=0;
while (index<currentSize/2) {//至少还有一个子节点 while node has at least one child
int leftChild =2*index+1;//leftChild
int rightChild =leftChild+1;//rightChild
System.out.println(" ----"+index);
if(rightChild < currentSize && heapArray[leftChild].getKey()<heapArray[rightChild].getKey()){
lagerChild=rightChild;
}else {
lagerChild=leftChild;
}
if (heapArray[lagerChild].getKey()<=top.getKey()) {
break;
}
heapArray[index]=heapArray[lagerChild];//
index=lagerChild;
}
heapArray[index]=top;
}
public boolean change(int index,int newValue){
if(index<0||index>=currentSize){//合法性
return false;
}
HeapNode node =heapArray[index];
if(newValue< node.getKey() ){
trickUp(index);
}else {
trickDown(index);
}
return true;
}
public void show(){
for(int i=0;i<currentSize;i++){
System.out.print(heapArray[i].getKey() + " |" );
}
System.out.println(" ---------------");
}
public int getCurrentSize(){
return currentSize;
}
public boolean isEmpty(){
return currentSize==0;
}
}
package alorgrithm;
public class HeapApp {
public static void main(String[] args) {
Heap heap =new Heap(10);
heap.insert(70);
heap.insert(40);
heap.insert(50);
heap.insert(20);
heap.insert(60);
heap.insert(100);
heap.insert(80);
heap.insert(30);
heap.insert(10);
heap.insert(90);
heap.show();
System.out.println("currrent="+heap.getCurrentSize());
heap.remove();
heap.show();
}
}