排序笔记_7(基于堆得优先队列)

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*2index*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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值