public class SiftUpComparable {
/**
* 构建最小堆代码
* @param index 将要入队的数组的角标
* @param value 将要入队的值
* @param array 数组
*/
public static void siftUpComparable(int index,int value,Integer[] array){
while(index>0){
// 得到父角标位置
int parent = (index-1)>>>1;
// 用父节点的值和将要入队的值进行比较,如果比父节点的值小则和父节点进行交换,因为这里构建的事小顶堆,所以要比较和交换比父节点的小的
// 如果父节点比将要插入的数据小,则直接退出
if(value>array[parent]){
break;
}
// 此时表示将要入队的节点数据比父节点的值要小,需要交换
// 把父节点的值拿出来,赋值给将要插入的数组角标的位置
int parentValue = array[parent];
array[index] = parentValue;
// 因为需要和父节点交换,因此使角标交换
index = parent;
}
array[index] = value;
}
/**
* 获取堆顶元素
* @param array
* @return
*/
public static int siftDownComparable(Integer[] array){
int n= array.length -1;
// 弹出的堆顶元素 最小的
int topValue = array[0];
// 最小堆中最后一个元素
int endKey = array[n];
// 将尾节点置为null
array[n] = null;
if(n<=0 ){
return 0;
}
// 循环次数为整个数据长度减一的一半,因为比较左节点从上到下依次比较,比较一次为一次循环,次数为 n>>>1
int half = n>>>1;
// 每次比较交换的的初始脚标,刚开始要从堆顶开始,也是 0,每次的值都是下一级节点中最小的那个值
int k = 0 ;
while(k<half){
//获取下一级左节点的脚标,child永远指向下一级两个节点中最小的节点角标
int child = (k<<1)+1;
//获取下一级右节点的脚标
int right = child+1;
// 获取下一级左节点的值 远指向下一级两个节点中最小的节点的值
int c = array[child];
// 如果right大于n,则证明此时没有右节点了
if(right<n && array[child]>array[right]){
c = array[child=right];
}
// 如果尾节点的值小于子节点的值,则退出本次循环,尾节点的值是要放入首节点角标为0的位置的
if(endKey<c){
break;
}
// 如果尾节点的值大于子节点的值,则需要交换,将首节点的值替换为比其小的子节点的值
array[k] = c;
// 将k的值下移为child
k = child;
}
// 将尾节点放入到合适的位置
array[k] = endKey;
return topValue;
}
public static void main(String[] args) {
Integer[] array = new Integer[5];
Random random = new Random();
System.out.println("入队 ");
for (int i = 0; i < 5; i++) {
int value = random.nextInt(100);
System.out.print(value+" ");
siftUpComparable(i, value, array);
}
print(array);
System.out.println();
System.out.println("出队");
System.out.println("出队的值 = "+siftDownComparable(array));
print(array);
}
public static void print( Integer[] array){
System.out.println();
for (int k=0;k<array.length;k++){
System.out.print(array[k]+" ");
}
}
}