1、什么是优先队列
2、堆的基础表示
二叉堆的2个性质:
下面介绍二叉堆的实现技巧:使用数组存储二叉堆(当然,也可以像前面的二分搜索树那样,通过左右指针的指定某个结点的左右孩子)
3、二叉堆的各类操作
代码如下:
package com.lkj;
//同样,二叉堆也是树,它里面的结点的值也必须要具有比较性,因为我们规定每一个结点的值必须大于等于它的孩子结点的值
// (大于需要使用compareTo(),如果只是等于重写equals()即可)
public class MaxHeap<E extends Comparable<E>>
{
//使用我们之前定义的动态数组保存二叉堆的元素
private Array<E> data;
public MaxHeap(int capacity)
{
data = new Array<>(capacity);//用户知道堆要存储多少元素:capacity
}
public MaxHeap()
{
data = new Array<>();//用户不知道堆要存储多少元素,不初始化数组容量
}
//-------------------------------------------------heapify:将任意数组整理成堆的形状
/**
* 分析:
* 方法1:将数组的每一个元素,使用堆的add()方法添加到堆中,由于每次添加一个元素,这个元素都要上浮到合适的位置,
* 那么添加n个元素,需要上浮n次,每次上浮的时间复杂度是 O(logn),这种方法的时间复杂度是 O(nlogn)
*
* 方法2:直接将这个数组看成一个堆,然后,我们找到在数组中下标最大的非叶子结点,从最大的非叶子结点开始,将这些数siftdown 到
* 合适的位置,最后就可以得到一个满足堆2个性质的堆,这种方法的时间复杂度是 O(n);
* 另外,下标最大的非叶子结点的 下标=最后一个结点父亲结点的下标!
*
* 我们将 heapify() 方法构造成为一个 构造方法
*/
//首先,我们需要给自己的 Array数组类创建一个:传入一个数组,将这个数组构造成为我们自己的动态数组的构造函数
public MaxHeap(E[] arr)
{
data = new Array<>(arr);//通过Array类的构造方法,将普通数组arr转换成为动态数组data,这样我们就可以使用动态数组的方法
//最后一个结点在数组的下标:data.getSize()-1;最后一个非叶子结点在数组的下标:parent(data.getSize()-1)
for (int i = parent(data.getSize()-1); i >= 0 ; i--)
{
siftDown(i);//将这个结点下沉到合适位置
}
}
//这样,通过这个方法我们就 可以通过数组 得到一个堆!
//--------------------------------------------------------------------------------
// 返回堆中的元素个数
public int size()
{
return data.getSize();
}
// 返回一个布尔值, 表示堆中是否为空
public boolean isEmpty()
{
return data.isEmpty();
}
//--------------------------------------下面是查找某个在数组中下标为index的结点的父亲结点、左右孩子结点在数组中的下标
// 返回完全二叉树的数组表示中,一个索引所表示的元素的父亲节点的索引
private int parent(int index)