/**
* 数据结构学习之队列之最大优先级队列接口
* @author Sking
*/
package 堆;
public interface MaxPriorityQueue {
/**
* 判断最大优先级队列是否为空
* @return 最大优先级队列为空则返回true,否则false
*/
public boolean isEmpty();
/**
* 返回最大优先级队列的元素个数
* @return 最大优先级队列的元素个数
*/
public int size();
/**
* 返回最大优先级队列的“最大”元素
* @return 最大优先级队列的“最大”元素,如果队列为空则返回null
*/
public Comparable<?> getMax();
/**
* 插入指定元素到最大优先级队列
* @param theObject 待插入元素
*/
public void put(Comparable<?> theObject);
/**
* 移除最大优先级队列的“最大”元素,并返回
* @return 最大优先级队列的“最大”元素,队列为空则返回null
*/
public Comparable<?> removeMax();
}
/**
* 数据结构学习之队列之最大优先级队列
* 使用数组形式的堆结构实现最大优先队列
* @author Sking*
*/
package 堆;
import java.lang.reflect.Array;
public class MaxHeap{
@SuppressWarnings("rawtypes")
Comparable[] heap;// 堆数组,索引位置0不使用
int size;// 元素个数
/**
* 指定堆数组初始容量的构造方法
*
* @param initialCapacity
* 堆数组的初始容量
*/
public MaxHeap(int initialCapacity) {
if (initialCapacity < 1)
throw new IllegalArgumentException("initialCapacity must be >= 1");
heap = new Comparable[initialCapacity + 1];
size = 0;
}
/**
* 无参构造函数,默认堆数组的初始容量为10
*/
public MaxHeap() {
this(10);
}
/**
* 判断堆数组是否为空
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 获取堆数组中的元素个数
*/
public int size() {
return size;
}
/**
* 获取堆数组中的首元素(“最大元素')
*/
@SuppressWarnings({ "rawtypes" })
public Comparable getMax() {
return (size == 0) ? null : heap[1];
}
/**
* 插入元素导最大堆中,重新调整使数组仍保持“堆特性”
*
* 实现方法:将插入元素放在数组尾部,递归比较当前元素与
* 父亲节点元素 不满足堆特性的条件,则递归向上往“根"的方
* 向冒泡(比较移动),直到新元素的父节点元素大于”它“
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void put(Comparable theElement) {
if (size == heap.length - 1) {// 堆数组已满,分配新空间
/*
* heap.getClass().getComponentType()
* 获取数组元素类型对应的Class对象
* Array.newInstance(Class<?>,int)
* 指定元素类型和数组长度创建新的数组实例
*/
Comparable[] newArray = (Comparable[]) Array.newInstance(heap
.getClass().getComponentType(), 2 * heap.length);
// 复制堆元素到新数组中
System.arraycopy(heap, 0, newArray, 0, heap.length);
heap = newArray;
}
int currentNode = ++size;// 新元素插入索引
// 新元素沿着到根的路径向上冒泡(比较交换),直到新元素的父结点元素“大于”它
while (currentNode != 1
&& heap[currentNode / 2].compareTo(theElement) < 0) {
// 父节点元素下移
heap[currentNode] = heap[currentNode / 2];
currentNode /= 2;
}
heap[currentNode] = theElement;
}
/**
* 从最大堆中移除堆数组的首元素(”最大元素“)
*
* 实现方法:先用堆数组的最后一个元素填补根节点,然后从根
* 位置开始 沿着不满足堆特性的路径递归进行调整,找到最后
* 一个元素的适合位置,使其成为最大堆。每次迭代均会涉及到
* 一棵子树(包含三个元素),找出 该子树中的最大元素作为当
* 前子树的根节点。如果最大元素就是数组末尾元素 则递归停止,
* 否则交换元素位置,并递归调整。
*
* 注意点:最大元素一开始就被保存,用于最后的返回值。所以调
* 整操作可以安全使用 首元素。并且调整以后数组末尾位置将空出。
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public Comparable removeMax() {
if (size == 0)// 堆数组为空
return null;
Comparable maxElement = heap[1];// ”最大"元素
Comparable lastElement = heap[size--];//堆数组的最后一个元素
int currentNode = 1, child = 2;//当前子树的根节点索引和左孩子索引
while (child <= size) {
// 每次迭代筛选出子树的最大元素作为该子树的根节点,交换元素位置
if (child < size && heap[child].compareTo(heap[child + 1]) < 0)
child++;
if (lastElement.compareTo(heap[child]) >= 0)
break;// 已满足最大堆特性
heap[currentNode] = heap[child];
currentNode = child;
child *= 2;
}// currentNode指示当前被考察的子树根节点位置
heap[currentNode] = lastElement;
return maxElement;
}
/**
* 将输入数组(长度为n)初始化为最大堆
* 实现方法:从有孩子节点的元素开始(索引为n/2),如果以该位置为根的子树
* 满足最大堆特性,则无需调整,否则通过交换位置进行调整。依次调整i,i-1,i-2..
* 位置为根的子树,直到数组的首元素为止。
* @param theHeap 输入的数组,可能不满足堆特性
* @param theSize 输入数组元素个数
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public void initialize(Comparable[] theHeap, int theSize) {
heap = theHeap;
size = theSize;
for (int root = size / 2; root >= 1; root--) {
Comparable rootElement = heap[root];
int child = 2 * root;
while (child <= size) {
if (child < size && heap[child].compareTo(heap[child + 1]) < 0)
child++;
if (rootElement.compareTo(heap[child]) >= 0)
break;
heap[child / 2] = heap[child];
child *= 2;
}
heap[child / 2] = rootElement;
}
}
/**
* 指定格式打印堆数组[元素1,元素2,元素3...]
*/
public String toString() {
StringBuffer s = new StringBuffer();
s.append("The " + size + " elements are [");
if (size > 0) {
s.append(heap[1]);
for (int i = 2; i <= size; i++)
s.append(", " + heap[i]);
}
s.append("]");
return new String(s);
}
}