这篇文字只方便已经了解最大堆,但又忘记最大堆怎么操作的人回忆
定义
- 父节点一定大于或者等于子节点
- 一般使用数组来表示二叉树
概念
上浮(shift Up)
我们将数值和父元素对比,如果大于父元素,则交换,直到小于父元素位置
下沉(Shift Down)
将当前节点的值和孩子节点中较大的节点交换,直到不能交换为止
操作
构建堆(方法1)
- 从第二个元素开始
- 对每个元素进行上浮操作
构建堆(方法2,建议)
- 从第最后一个不是叶子节点的元素开始
- 对元素进行下层操作
- 移动到前一个元素
插入元素
- 将新元素放置到末尾
- 然后进行上浮
取出最大元素
- 取出最大元素(根节点)
- 将末尾的值移动到根节点
- 然后将最大元素进行下层
代码
下面我实现的是最小堆,最大堆大家可以自己尝试
public class MinHeap {
int[] nums = new int[1690 * 3];
int length = 0;//长度
public static void main(String[] args) {
MinHeap minHeap = new MinHeap();
minHeap.add(1);
minHeap.add(2);
minHeap.add(3);
minHeap.add(5);
minHeap.add(4);
minHeap.add(6);
minHeap.add(10);
minHeap.add(9);
minHeap.add(15);
while (minHeap.length > 0) {
System.out.println(minHeap.get());
}
}
/**
* 用方法二进行创建
*/
public void create(){
//找到最后一个非叶子节点,即:最后一个元素的父元素
int fIndex = getFIndex(length - 1);
for (int i = fIndex; i >= 0 ; i--) {
shiftDown(i);
}
}
public void add(int cur){
if(cur < 0){
return;
}
nums[length] = cur;
length++;
shiftUp(length-1);
}
public int get(){
if(length == 0){
new ArrayIndexOutOfBoundsException();
}
int max = nums[0];
length--;
nums[0] = nums[length];
shiftDown(0);
return max;
}
/**
* 上浮
* @param curIndex
*/
private void shiftUp(int curIndex){
if(curIndex == 0){
return;
}
int fIndex = getFIndex(curIndex);
if(nums[curIndex] < nums[fIndex]){
int temp = nums[curIndex];
nums[curIndex] = nums[fIndex];
nums[fIndex] = temp;
shiftUp(fIndex);
}
}
/**
* 下沉
* @param curIndex
*/
private void shiftDown(int curIndex){
int lChildIndex = getLCIndex(curIndex);
if(lChildIndex >= length){ //说明没有子节点了
return;
}
int rChildIndex = getRCIndex(curIndex);
int minChildIndex = 0;
if(rChildIndex >= length){ // 如果右子节点已经越界
minChildIndex = lChildIndex;
} else if(nums[lChildIndex] < nums[rChildIndex]){ //如果 “左子节点” 小于 “右子节点”
minChildIndex = lChildIndex;
} else {
minChildIndex = rChildIndex;
}
if(nums[curIndex] > nums[minChildIndex]){
int temp = nums[curIndex];
nums[curIndex] = nums[minChildIndex];
nums[minChildIndex] = temp;
shiftDown(minChildIndex);
}
}
/**
* 得到父节点的下标
* @param curIndex
* @return
*/
private int getFIndex(int curIndex){
return (curIndex -1) / 2;
}
/**
* 得到左子节点的下标
* @param curIndex
* @return
*/
private int getLCIndex(int curIndex){
return curIndex*2 + 1;
}
/**
* 得到右子节点的下标
* @param curIndex
* @return
*/
private int getRCIndex(int curIndex){
return curIndex*2 + 2;
}
}