上图红色代表树节点索引;
左子节点和父节点的索引关系是 : 2*n
右子节点和父节点的索引关系是 : 2*n +1
package demo;
/**
*
* @author Administrator
* 最大树----------------------------------------
*/
public class MaxHeap {
//定义这个堆最大能存多少个元素
public static int[] data;
//记录当前索引位置,因为图中是第一个元素不是0,而是从1开始记录的
public static int count;
private static int size;
//默认构造初始化堆空间大小
protected MaxHeap (int size) {
this.data = new int[size+1];
count = 0;
this.size = size;
}
protected int size(){return count; };
//向堆中添加元素
public static void insert(int item){
assert count + 1 <= size;
//将当前元素存入到堆结构中,因为从下表从一开始的所以,记录索引的值得+1
data[count+1] = item;
//更新记录值
count ++;
//到目前为止我们只是添加了一个元素,为了满足最大堆的特点即父节点大于两个子节点所以得对当前新添加的元素
//从新更新为止,直到符合最大堆得要求
shiftUp(count);
}
/**
* 取出最大元素的规则如下:
* 1,将当前堆中最大的元素,也就是第一个结点,与最后一个节点交换值;
* 2,记录索引的count进行自减一,相当于剔除交换后整个堆得最后一个元素,也就是之前的第一个元素
* 3,最后判断这个新的头节点,也就是第一个元素是否满足最大推得特点。
*/
public void extractMax(){
//获取第一个元素
int returns = data[1];
//将头节点与最后一个节点进行交换
switchs(count,1);
count--; //忽略最后一个元素
//对新的头节点进行交换,直至满足最大堆得条件
shiftDown(1);
System.out.print(returns);
};
static void shiftUp(int k){
//当前传入节点的索引即为新加元素的节点,父节点索引即为 k/2,如果子节点大于父节点,进行交换
while( k > 1 && data[k] > data[k/2]){
//置换两个节点的值
switchs(k,k/2);
//更新k的值,继续循环,直到所有的数据都满足条件
k =k/2;
}
}
static void shiftDown(int l){
//判断当前节点是否有左节点,有的话执行
while(2*l <= count){
int itrmchange = 2*l;
//itrmchange +1 也就是右节点是否存在,并且如果右节点大于左节点的值,那么头节点跟父节点进行置换
//否则与左节点置换
if(itrmchange +1 <= count && data[itrmchange+1]>data[itrmchange])
itrmchange=itrmchange+1;
//继续判断头结点是否大于子节点,满足跳出循环
if(data[l] >= data[itrmchange])
break;
//否则继续交换值
switchs(l, itrmchange);
//更新节点
l=itrmchange;
}
}
//交换两个节点值
static void switchs(int i,int j){
int t = data[i];
data[i] =data[j];
data[j] = t;
};
}
工具测试类:
package bobo.algo;
import demo.MaxHeap;
// 我们的PrintableMaxHeap只能处理整数信息,所以继承的是MaxHeap<Comparable<Integer>>
public class PrintableMaxHeap extends MaxHeap{
public PrintableMaxHeap(int capacity){
super(capacity);
}
// 以树状打印整个堆结构
public void treePrint(){
if( size() >= 100 ){
System.out.println("This print function can only work for less than 100 integer");
return;
}
System.out.println("The max heap size is: " + size());
System.out.println("Data in the max heap: ");
for( int i = 1 ; i <= size() ; i ++ ){
// 我们的print函数要求堆中的所有整数在[0, 100)的范围内
assert (Integer)data[i] >= 0 && (Integer)data[i] < 100;
System.out.print(data[i] + " ");
}
System.out.println();
System.out.println();
int n = size();
int maxLevel = 0;
int numberPerLevel = 1;
while( n > 0 ){
maxLevel += 1;
n -= numberPerLevel;
numberPerLevel *= 2;
}
int maxLevelNumber = (int)Math.pow(2, maxLevel-1);
int curTreeMaxLevelNumber = maxLevelNumber;
int index = 1;
for( int level = 0 ; level < maxLevel ; level ++ ){
String line1 = new String(new char[maxLevelNumber*3-1]).replace('\0', ' ');
int curLevelNumber = Math.min(count-(int)Math.pow(2,level)+1,(int)Math.pow(2,level));
boolean isLeft = true;
for( int indexCurLevel = 0 ; indexCurLevel < curLevelNumber ; index ++ , indexCurLevel ++ ){
line1 = putNumberInLine( (Integer)data[index] , line1 , indexCurLevel , curTreeMaxLevelNumber*3-1 , isLeft );
isLeft = !isLeft;
}
System.out.println(line1);
if( level == maxLevel - 1 )
break;
String line2 = new String(new char[maxLevelNumber*3-1]).replace('\0', ' ');
for( int indexCurLevel = 0 ; indexCurLevel < curLevelNumber ; indexCurLevel ++ )
line2 = putBranchInLine( line2 , indexCurLevel , curTreeMaxLevelNumber*3-1 );
System.out.println(line2);
curTreeMaxLevelNumber /= 2;
}
}
private String putNumberInLine( Integer num, String line, int indexCurLevel, int curTreeWidth, boolean isLeft){
int subTreeWidth = (curTreeWidth - 1) / 2;
int offset = indexCurLevel * (curTreeWidth+1) + subTreeWidth;
assert offset + 1 < line.length();
if( num >= 10 )
line = line.substring(0, offset+0) + num.toString()
+ line.substring(offset+2);
else{
if( isLeft)
line = line.substring(0, offset+0) + num.toString()
+ line.substring(offset+1);
else
line = line.substring(0, offset+1) + num.toString()
+ line.substring(offset+2);
}
return line;
}
private String putBranchInLine( String line, int indexCurLevel, int curTreeWidth){
int subTreeWidth = (curTreeWidth - 1) / 2;
int subSubTreeWidth = (subTreeWidth - 1) / 2;
int offsetLeft = indexCurLevel * (curTreeWidth+1) + subSubTreeWidth;
assert offsetLeft + 1 < line.length();
int offsetRight = indexCurLevel * (curTreeWidth+1) + subTreeWidth + 1 + subSubTreeWidth;
assert offsetRight < line.length();
line = line.substring(0, offsetLeft+1) + "/" + line.substring(offsetLeft+2);
line = line.substring(0, offsetRight) + "\\" + line.substring(offsetRight+1);
return line;
}
// 测试 PrintableMaxHeap
public static void main(String[] args) {
PrintableMaxHeap maxHeap = new PrintableMaxHeap(10);
int N = 10; // 堆中元素个数
int M = 100; // 堆中元素取值范围[0, M)
for( int i = 0 ; i < N ; i ++ )
maxHeap.insert( new Integer((int)(Math.random() * M)) );
maxHeap.treePrint();
System.out.print("*************************************");
int m = 0;
while( m <5){
maxHeap.extractMax();
maxHeap.treePrint();
//System.out.print(extractMax);
m++;
}
}
}
执行结果: