参考
堆就是利用数组来实现二叉树,可用于构建优先队列、堆排序、TopK问题等。可分为:
- 最大堆:父节点的值比其子节点大
- 最小堆:父节点的值比其子节点小
堆的根节点存放了最小(或最大)元素,但是其它节点的排序是未知的,即左节点不一定比右节点大(或小),堆的搜索相对于二叉搜索树更慢,二叉搜索树(如AVL)是平衡二叉树,搜索时间复杂度为O(nlogn),而堆的目的只是为了获得最大(或最小)元素,将其存储在头节点。
实现堆只需要一个顺序存储结构的数组,相对于二叉树而言,空间开销更低,二叉树还需要分配左右指针占用内存更多。
假设父节点的位置为i
(节点下标从0开始),则其左孩子位置为2i+1
,右孩子位置为2i+2
,这种存储方式与完全二叉树使用数组存储是一样的。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200718100824998.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
1. 建立最大堆
创建堆数组,将给定数组拷贝给堆数组;调整堆,从最后一个非叶节点开始进行shiftdown
下滑操作,如下图,从97开始往前调整堆,将当前节点与其孩子节点进行比较,若孩子节点大于父节点,则将父节点下滑,孩子节点上浮
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719104503753.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
97和65均比孩子节点大不需下浮,节点38比孩子节点97、76都要小,将其与较大的97节点进行交换
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719104817772.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
交换后需要进行递归,直到下浮的38节点比孩子节点小
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719105131317.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
最后38节点被交换到了叶子节点
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719105332170.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
建堆完成后如下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719105420896.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70)
2.插入新节点
在建立最大堆后,插入节点有可能破坏堆的结构,插入的节点被放到堆的尾部,如下,插入节点85,此时85比父节点49大,不满足最大堆结构
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719105821702.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
此时需要沿着以下路径将节点85上浮shiftup
操作
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719110032551.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
最后85节点调整到如下位置
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719110125977.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
3.删除根节点
如下删除根节点97
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719110439480.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
将尾部节点替换到根节点,然后从根节点开始进行shiftdown
下滑操作
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719110527808.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
调整后堆的结构如下,节点49被下浮到第3层
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200719110738577.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ4Njc4MA==,size_16,color_FFFFFF,t_70#pic_center)
4.JAVA实现
class maxHeap {
private int MAX_SIZE, NOW_SIZE, HEAP[];
public maxHeap(int nums[]) {
MAX_SIZE = 100;
HEAP = new int[MAX_SIZE];
for (int i = 0; i < nums.length; i++) {
HEAP[i] = nums[i];
NOW_SIZE++;
}
for (int i = NOW_SIZE / 2 - 1; i >= 0; i--) {
shiftdown(i);
}
}
public void shiftdown(int ind) {
int left_child = 2 * ind + 1;
int right_child = 2 * ind + 2;
int large_ind = ind;
if (left_child < NOW_SIZE && HEAP[large_ind] < HEAP[left_child]) {
large_ind = left_child;
}
if (right_child < NOW_SIZE && HEAP[large_ind] < HEAP[right_child]) {
large_ind = right_child;
}
if (large_ind != ind) {
int temp = HEAP[large_ind];
HEAP[large_ind] = HEAP[ind];
HEAP[ind] = temp;
shiftdown(large_ind);
}
}
public void shiftup(int ind) {
int parent = (int) (ind - 1) / 2;
if (parent >= 0 && HEAP[parent] < HEAP[ind]) {
int temp = HEAP[parent];
HEAP[parent] = HEAP[ind];
HEAP[ind] = temp;
shiftup(parent);
}
}
public void insert(int val) {
if (NOW_SIZE < MAX_SIZE - 1) {
HEAP[NOW_SIZE] = val;
shiftup(NOW_SIZE);
NOW_SIZE++;
}
}
public void delete() {
HEAP[0] = HEAP[NOW_SIZE - 1];
NOW_SIZE--;
shiftdown(0);
}
public void printHeap() {
for (int i = 0; i < NOW_SIZE; i++)
System.out.print(HEAP[i] + " ");
System.out.println();
}
}
public class main {
public static void main(String[] args) {
int nums[] = { 1, 2, 7, 9, 3, 8, 5, 6, 7 };
maxHeap heap = new maxHeap(nums);
heap.printHeap();
heap.insert(10);
heap.printHeap();
heap.insert(5);
heap.printHeap();
heap.delete();
heap.printHeap();
heap.delete();
heap.printHeap();
}
}
5.堆排序
在建好堆后,可以进一步实现堆排序,由于堆顶始终是最小(或最大)元素,因此每次取出堆顶元素然后将末尾元素替换到堆顶,并从堆顶进行shiftdown
下浮操作调堆,即可完成堆排序。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)