索引式优先队列(indexed priority queue)

为了达到O(ElogV)的效率,需要对普利姆算法进行eager实现。 如果我们用java来做,jdk当中的priorityQueue并不能满足我们的要求。 因为我们需要进行一个对索引元素降key的操作(decrease-key)./** * 将索引所关联的key降到newKey * * @param index 索引 * @param newKey 新的k
摘要由CSDN通过智能技术生成

为了达到O(ElogV)的效率,需要对普利姆算法进行eager实现。
如果我们用java来做,jdk当中的priorityQueue并不能满足我们的要求。
因为我们需要进行一个对索引元素降key的操作(decrease-key).

/**
     * 将索引所关联的key降到newKey
     *
     * @param index 索引
     * @param newKey 新的key
     */
    public void decreaseKey(int index, E newKey) {
        if (index < 0 || index >= queue.length)
            throw new IndexOutOfBoundsException();
        if (newKey == null)
            throw new NullPointerException();
        if (!contains(index))
            throw new NoSuchElementException("指定的索引不存在!");
        if (this.comparator() != null) {
            if (this.comparator().compare((E) keys[index], newKey) <= 0)
                throw new IllegalArgumentException("指定的key必须小于原索引关联的key!");
        } else {
            Comparable<? super E> key = (Comparable<? super E>) getKeyOf(index);
            if (key.compareTo(newKey) <= 0)
                throw new IllegalArgumentException("指定的key必须小于原索引关联的key!");
        }

        keys[index] = newKey;
        siftUp(getPositionOf(index));
    }

由于需要知道优先队列中元素的索引以支持外部索引式访问,我们将对priorityQueue中的Queue建立索引,并将此索引当作二叉堆实际存储的元素,而原来的元素我们通过索引表来访问它.

    /**
     * 索引所关联的keys
     */
    private transient Object[] keys;
    /**
     * 建立一个从索引在二叉堆中的位置到索引的映射
     */
    private transient int[] queue;

这里还有一个问题,就是在进行上浮(siftUp)和下沉(siftDown)时,需要对堆中的元素和位置进行互访,我们还需要建立一个索引到位置的倒排,或者索引到位置的一个映射.

    /**
     * 建立一个从索引到其在二叉堆中位置的映射,下标是关联key的索引
     */
    private transient int[] postQueue;

这样我们就可以按下面的方式访问二叉堆中的索引、它在二叉堆中的位置、以及它关联的key:

/**
     * 返回给定位置的索引
     *
     * @param position 二叉堆中的位置
     * @return 给定位置的索引
     */
    private int getIndexOf(int position) {
        return queue[position];
    }

    /**
     * 返回给定索引在二叉堆中的位置
     *
     * @param index 索引
     * @return 给定索引在二叉堆中的位置
     */
    private int getPositionOf(int index) {
        return postQueue[index];
    }
    /**
     * 返回给定索引所关联的key
     *
     * @param index 索引
     * @return 索引所关联的key
     */
    private E getKeyOf(int index) {
        return (E) keys[index];
    }

而交换元素时,需要先交换索引,然后再维护索引到位置的映射:

/**
     * 按位置交换
     *
     * @param x 一个元素的位置
     * @param y 另一个元素的位置
     */
    private void exchangeByPosition(int x, int y) {
        int tmp = queue[x];
        queue[x] = queue[y];
        queue[y] = tmp;

        postQueue[queue[x]] = x;
        postQueue[queue[y]] = y;
    }

这样,我们的上浮操作看起来是这样的:

    private void siftUpComparable(int k) {
        Comparable<? super E> key = (Comparable<? super E>) keys[getIndexOf(k)];
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = keys[queue[parent]];
            if (key.compareTo((E) e) >= 0)
                break;
            exchangeByPosition(k, parent);
            k = parent;
        }
    }

而下沉操作就变成了这样:

<
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值