要点:
- 了解 shiftDown
- 了解优先队列 出队的机制
上一篇文章中我写了优先队列的入队操作,入队shiftUp,出队shiftDown
看代码效果:
首先,在优先队列插入50个元素,执行poll操作,也就是出队
把队顶的一个元素拿出
如图,2个97只剩下一个
对于一个50个元素的大根堆,只要出队,就变成49个元素,这里我使用 count–,因此数组长度并不是真的变成了49个,而是模拟 了一个出队,第50个元素还是存在的,这个大根堆的容量只有100个
当大根堆满了之后,要重新创建一个数组,维护一个新的大根堆,这个功能我就暂时先不实现了
出队主要是把队首和队尾的元素交换,然后执行shiftDown 操作,也就是和他的儿子,比较,如果父亲比儿子小,儿子上来,父亲下去,重复这个操作,你就又维持了一个大根堆,具体可以看我的上一篇文章, 优先队列的入队操作
package day1;
import util.AlgoVisHelper;
import util.AlgoVisualizer;
import java.util.*;
/**
* Created by ASUS on 2019/8/22.
*/
public class Main {
public static void main(String[] args) {
Random r = new Random();
MaxHeap p = new MaxHeap(100);
int n = 50;
int m =100;
for(int i=0;i<n;++i) {
int t = r.nextInt(100);
p.insert(t);
}
p.treePrint();
System.err.println("----------------------------------------------------------------");
int big = p.poll();
System.err.println("------ big " +big + " -----------------------");
p.treePrint();
}
}
class MaxHeap {
int[] data;
int count;
int capacity;
public MaxHeap(int capacity) {
this.capacity = capacity;
data = new int[capacity];
this.count=0;
}
int size() {
return count;
}
public boolean isEmpty() {
return count==0;
}
void insert(int e) {
data[count+1]=e;
count++;
shiftUp(count);
}
void swap(int i,int j) {
if(data[i]==data[j])return;
data[i]^=data[j];
data[j]^=data[i];
data[i]^=data[j];
}
void shiftUp(int k) {
while (k>1&&data[k]>data[k/2])
{
swap(k,k/2);
k/=2;
}
}
int poll() {
if(count<0)return 0;
int ret = data[1];
swap(1,count);
count--;
shiftDown(1);
return ret;
}
void shiftDown(int k) {
while (2*k<=count) {
int j = 2*k;
if(j+1<=count&&data[j+1]>data[j]) {//尽量和大的交换
j+=1;
}
if(data[k]>=data[j]) {
break;
}
swap(k,j);
k=j;
}
}
public void treePrint() {
// 最多打印100个元素
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 = 0; i < size(); i++) {
// 我们的print函数要求堆中的所有整数在[0, 100]的范围内
assert (Integer) data[i] >= 0 && (Integer) data[i] < 100;
System.out.println(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;
}
}