索引优先队列的实现

注:此文需要对有序二叉堆、优先队列等知识有所了解,建议看完用有序二叉堆实现优先队列后再阅读此文

背景

普通优先队列(不带索引)只能访问有序二叉堆的根节点,而无法引用队列中的其它任何元素。

特点

索引优先队列中存储的元素都有对应的“索引”,通过“索引”我们可以引用该索引对应的元素。可以理解为HashMap中的key-value,key即索引,value即所对应的元素。

实现要点

  • 数组T[] a存放所有的元素,数组的下标对应该元素的索引,元素在该数组中是无序的。
  • 数组int[] pq 存放所有元素的索引,pq要实现为优先队列(即有序二叉堆的结构),索引在pq中是有序的
  • 数组int[] qp是pq的“倒置”数组,下标为元素的索引,若pq[i] = k,则pq[k] = i。默认情况下存放-1,此数组用来通过索引拿到在二叉堆(pq)中的节点位置。

代码实现

public class IndexMaxPQ<T extends Comparable<T>>{
    private int N = 0;//队列大小
    private int index = 0;//队列中元素个数
    private T[] a;//存放元素
    private int[] pq;//存放索引
    private int[] qp;//存放索引在pq中的下标,索引不存在的话为-1

    public IndexMaxPQ(int size){
        N = size;
        for(int i = 0; i < N; i++){
            qp[i] = -1;
        }//qp全部初始化为-1
        a = (T[])new Comparable<T>(N + 1);
        pq = new int[](N + 1);
        qp = new int[](N + 1);
    }

    public void insert(int k, T item){
        if (contains(k)) {
            throw new IllegalArgumentException("index is already in the priority queue");
        }
        a[k] = item;//保存元素
        pq[++index] = k;//保存索引在二叉堆末尾
        qp[k] = index;//保存索引对应的二叉堆节点位置(暂时在末尾,在swim中会更新节点位置)
        swim(index);//上浮至正确节点
    }

    public boolean contains(int k){
        return qp[k] != -1;//-1表明索引没有对应的节点位置
    }

    public void delete(int k){
        int j = qp[k];//通过索引取出节点位置
        pq[j] = pq[index];//用末尾节点覆盖当前节点
        pq[index] = null;//末尾节点置null
        sink(j);//下沉至正确节点位置
        qp[k] = -1;//索引被删除,相当于二叉堆中无此节点位置
        a[k] = null;//元素置null
        index--;
    }

    public T delMax(){
        T max = a[pq[1]];

        int k = pq[1];
        a[k] = null;

        pq[1] = pq[index--];
        sink(1);

        qp[k] = -1;
        return T;
    }
        //上浮动作,可参考[用有序二叉堆实现优先队列](http://blog.csdn.net/a854702872/article/details/77687288)
    private void swim(int j){
        while (j > 1) {
            if (a[pq[j/2]] < a[pq[j]]) {//注意比较的是索引对应的元素,即a[]中的值
                swap(j/2, j);
                j = j / 2;
            } else{
                break;
            }
        }
    }

    private void swap(int m, int n){
        int iTemp = pq[m];
        pq[m] = pq[n];
        pq[n] = iTemp ;//交换索引

        qp[pq[m]] = m;//索引对应的节点位置更新
        qp[pq[n]] = n;
    }
    //下沉动作,可参考[用有序二叉堆实现优先队列](http://blog.csdn.net/a854702872/article/details/77687288)
    private void sink(int j){
        while (j * 2 < N) {
            int m = j * 2;
            if (a[pq[m]] < a[pq[m++]]) {m++;}
            if (a[pq[j]] > a[pq[m]]) {break;}
            swap(j, m);
            j = m;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值