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

本文介绍了一个Java实现的索引优先队列,适用于优化如普利姆算法中的最轻边查找。队列支持最小优先和最大优先,并提供增加、删除、查找等操作,保证堆的不变性。通过索引可以快速访问元素,同时提供了调整键值的方法以维护优先级。
摘要由CSDN通过智能技术生成

import java.util.*;

/**

* Created by 浩然 on 4/19/15.

* 索引式优先队列

*

* 建立目的:

* 在实现普利姆算法时,需要用优先队列来优化最轻边的查找.

* 而jdk中的优先队列只满足lazy实现,如果要作eager实现,需实现一个decrease-key操作.

*

* 参考:

* 1.普林斯顿大学 algorithms 4th edition.

* 2.jdk priorityQueue.

*

* 说明:

* 1.队头是最least的元素

* 2.可通过自定义Comparable或Comparator实现最大优先、最小优先队列.

* 3.假设是最小优先队列,堆的不变性是指,任何插入、删除、出队、入队的操作都满足以下性质:

* 任何一个父元素的key都不大于子元素的key

* 而对于最大优先队列,则需满足任何一个父元素的key都不小于子元素的key

*/

public class IndexPriorityQueue {

private static final int DEFAULT_INITIAL_CAPACITY = 11;

/**

* 索引所关联的keys

* 以O(1)的时间找出给定索引所关联的key

*/

private transient Object[] keys;

//建立下面两个辅助字段的目的:

//1:以O(1)的时间找到给定索引的位置

//2:以O(1)的时间找到给定位置的索引

/**

* 建立一个从索引在二叉堆中的位置到索引的映射,下标就是索引在二叉堆中的位置

*/

private transient int[] queue;

/**

* 建立一个从索引到其在二叉堆中位置的映射,下标是关联key的索引

*/

private transient int[] postQueue;

private int size = 0;

private final Comparator super E> comparator;

public IndexPriorityQueue() {

this(DEFAULT_INITIAL_CAPACITY, null);

}

public IndexPriorityQueue(int initialCapacity) {

this(initialCapacity, null);

}

public IndexPriorityQueue(int initialCapacity,

Comparator super E> comparator) {

if (initialCapacity < 1)

throw new IllegalArgumentException();

this.keys = new Object[initialCapacity];

this.queue = new int[initialCapacity];

this.postQueue = new int[initialCapacity];

for (int i = 0; i < postQueue.length; i++) {

postQueue[i] = -1;

}

this.comparator = comparator;

}

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

/**

* 扩容

*

* @param minCapacity 所需的最小容量

*/

private void grow(int minCapacity) {

int oldCapacity = keys.length;

int newCapacity = oldCapacity + ((oldCapacity < 64) ?

(oldCapacity + 2) :

(oldCapacity >> 1));

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

keys = Arrays.copyOf(keys, newCapacity);

queue = Arrays.copyOf(queue, newCapacity);

postQueue = Arrays.copyOf(postQueue, newCapacity);

}

private static int hugeCapacity(int minCapacity) {

if (minCapacity < 0)

throw new OutOfMemoryError();

return (minCapacity > MAX_ARRAY_SIZE) ?

Integer.MAX_VALUE :

MAX_ARRAY_SIZE;

}

/**

* 返回队列是否为空

*

* @return 队列空则返回真,否则返回假

*/

public boolean isEmpty() {

return size == 0;

}

/**

* 将index关联的key加入队列

*

* @param index 索引

* @param key key

* @return

*/

public boolean offer(int index, E key) {

if (index < 0)

throw new IndexOutOfBoundsException();

if (key == null)

throw new NullPointerException();

int last = size;

//是否需要扩容

if (last >= keys.length)

grow(last + 1);

size = last + 1;

//首先将元素加入到队尾,然后从队尾上浮,直到满足堆的不变性

//index到position的映射

postQueue[index] = last;

//position到index的映射

queue[last] = index;

//保存index关联的key

keys[index] = key;

if(last == 0)

return true;

//上浮

siftUp(last);

return true;

}

/**

* 返回最优先元素,并且不删除此元素

*

* @return

*/

public int peek() {

if (size == 0)

return -1;

return getIndexOf(0);

}

/**

* 队列中是否包含指定的元素

*

* @param index 索引

* @return 如果指定的索引在队列中,返回真,否则返回假

*/

public boolean contains(int index) {

return getPositionOf(index) != -1;

}

/**

* 队列的长度

*

* @return

*/

public int size() {

return size;

}

/**

* 清空队列

*/

public void clear() {

for (int i = 0; i < size; i++) {

if (postQueue[i] < 0)

continue;

int index = getIndexOf(i);

keys[index] = null;

postQueue[index] = -1;

queue[i] = -1;

}

size = 0;

}

/**

* 返回最优先的元素并在队列中删除此元素

*

* @return 最优先的元素, 如果为负,表示队列已空

*/

public int poll() {

if (size == 0)

return -1;

int tail = --size;

int head = getIndexOf(0);

if(tail != 0){

exchangeByPosition(0, tail);

siftDown(0);

}

postQueue[head] = -1;

//队尾的元素经过交换后就是之前的队头,现在可以删除了

keys[getIndexOf(tail)] = null;

queue[tail] = -1;

return head;

}

private int remove(int index) {

assert index >= 0 && index < size;

if (!contains(index))

return -1;

int s = --size;

int position = getPositionOf(index);

//将堆中最后一个元素和要删除的元素交换

exchangeByPosition(position, s);

siftUp(position);

siftDown(position);

//help gc

keys[index] = null;

//标记在堆中已无此元素

postQueue[index] = -1;

return -1;

}

/**

* 上浮元素

*

* @param k 上浮开始的位置

*/

private void siftUp(int k) {

if (comparator != null)

siftUpUsingComparator(k);

else

siftUpComparable(k);

}

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;

}

}

private void siftUpUsingComparator(int k) {

E key = (E) keys[getIndexOf(k)];

while (k > 0) {

int parent = (k - 1) >>> 1;

Object e = keys[queue[parent]];

//如果key不小于其父节点的key,break

if (comparator.compare(key, (E) e) >= 0)

break;

//否则交换current、parent处的元素

exchangeByPosition(k, parent);

//继续上浮

k = parent;

}

}

/**

*

* @param k

*/

private void siftDown(int k) {

if (comparator != null)

siftDownUsingComparator(k);

else

siftDownComparable(k);

}

/**

* 按位置交换

*

* @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 siftDownComparable(int k) {

Comparable super E> key = (Comparable super E>) getKeyOf(getIndexOf(k));

int half = size >>> 1;

while (k < half) {

int child = (k << 1) + 1;

Object c = getKeyOf(getIndexOf(child));

int right = child + 1;

if (right < size &&

((Comparable super E>) c).compareTo(getKeyOf(getIndexOf(right))) > 0)

c = getKeyOf(getIndexOf(child = right));

if (key.compareTo((E) c) <= 0)

break;

exchangeByPosition(k, child);

k = child;

}

}

private void siftDownUsingComparator(int k) {

E x = getKeyOf(getIndexOf(k));

int half = size >>> 1;

while (k < half) {

//假设作孩子是least

int child = (k << 1) + 1;

Object c = keys[child];

int right = child + 1;

//如果右孩子更小,那就和右孩子比较

if (right < size &&

comparator.compare((E) c, getKeyOf(getIndexOf(right))) > 0)

c = getKeyOf(getIndexOf(child = right));

//当元素不大于它的所有孩子时停止

if (comparator.compare(x, (E) c) <= 0)

break;

//否则交换元素和它最小的孩子

exchangeByPosition(k, child);

//继续下沉

k = child;

}

}

/**

* 将索引所关联的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));

}

/**

* 将索引所关联的key升到newKey

*

* @param index 索引

* @param newKey 新的key

*/

public void increaseKey(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;

siftDown(getPositionOf(index));

}

/**

* 调整队列以保证堆的不变性

*/

private void heapify() {

for (int i = (size >>> 1) - 1; i >= 0; i--)

siftDown(i);

}

public Comparator super E> comparator() {

return comparator;

}

/**

* 返回给定位置的索引

*

* @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];

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值