package com.chapter_two;
/***
* 基于堆(二叉堆)得优先队列
*
* 二叉堆表示法:
*
* 如果我们用指针来表示堆有序的二叉树,那么每个元素都需要三个指针来找到它的上下节点,父节点和两个子节点。
*
* 如果用完全二叉树,表达就方便多了。完全二叉树只用数组而不需要指针就可以表示。
*
* 具体做法:将二叉树的节点按照层级顺序放入数组中,根节点在位置1,它的子节点在位置2和3,
*
* 而子节点的子节点则分别放在位置4,5,6和7,以此类推。
*
* 改进:动态调整数组大小。
*
* API
*
* MaxPQ(int maxN) 创建一个优先队列
*
* void insert(Key v) 向优先队列插入一个元素
*
* Key delMax() 删除并返回最大元素
*
* boolean isEmpty() 返回队列是否为空
*
* int size() 返回优先队列中的元素个数
*
* @author LuodiJack
*
*/
public class MaxPQ<Key extends Comparable<Key>> {
// 上一行的写法详见 http://blog.csdn.net/A199581/article/details/50727730
private Key[] pq;// pq[0]是不存储数据的
private int N = 0;// 数组的大小
@SuppressWarnings("unchecked")
public MaxPQ(int maxN) {
pq = (Key[]) new Comparable[maxN + 1];// 特别注意这 详见:[http://blog.csdn.net/a199581/article/details/50727730]
}
public int size() {
return N;
}
public boolean isEmpty() {
return N == 0;
}
/***
* 将需要插入的元素插入到末尾,然后利用上浮法(swim()),
*
* 将此元素放到合适的位置。
*
* @param v
* 要插入的元素
*/
public void insert(Key v) {
pq[++N] = v;
swim(N);
}
/***
* 将最大元素存下来,把最大的元素(即 第一个元素 pq[1])和数组中的最后一个元素交换位置,
*
* 将最大的元素清除,然后利用下沉(sink())的方法将第一个元素放到合适的位置。
*
* @return 此时所有元素中的最大值
*/
public Key delMax() {
Key max = pq[1];
exch(1, N--);
pq[N + 1] = null;// 防止对象游离
sink(1);
return max;
}
private void exch(int i, int j) {
Key tmp = pq[i];
pq[i] = pq[j];
pq[j] = tmp;
}
/***
* 一个元素的索引若为index,那么他的父节点(如果有的话)的索引一定是 index/2,
*
* 他的孩子节点(如果有的话)的索引一定是 index*2 和 index*2+1。
*
* 所以,swim(int index)方法:
*
* 一层一层的向上比较,如果自己比父节点的值要大,那就交换位置,直到他的父亲节点大于他。
*
* @param index
* 索引
*/
private void swim(int index) {
while (index > 1 && less(index / 2, index)) {
exch(index / 2, index);
index = index / 2;
}
}
/***
* 如果自己的值要小于子节点,那么就与子节点交换位置,直到自己比所有的子节点都要大。
*
* @param index
* 索引
*/
private void sink(int index) {
while (index * 2 <= N) {
int j = index * 2;
if (j < N && less(j, j + 1)) {// 找出子节点中最大的那一个,因为只要父节点比任意的一个子节点小,都要交换位置。
j++;
}
if (!less(index, j)) {
break;
}
exch(index, j);
index = j;
}
}
private boolean less(int i, int j) {
return pq[i].compareTo(pq[j]) < 0;
}
}
排序笔记_7(基于堆得优先队列)
最新推荐文章于 2023-05-31 23:55:20 发布