Java中的Priority Queue,用于跟踪每个节点的位置

时间:2014-05-05 01:01:26

标签: java algorithm priority-queue binary-heap

所以我正在为我的班级做一个实验室。我需要使用数组列表在Java中创建Priority Queue。踢球者是每个节点必须有一个“句柄”,它只是一个对象,它包含与之关联的节点的索引。我知道这听起来很奇怪,但我们必须以这种方式实现它。无论如何,我的优先级队列似乎工作正常,除了句柄值显然没有正确更新,因为我没有通过句柄测试。另外,我在调用extractMin()之后才遇到句柄问题,所以我认为问题会出现在那个方法的某个地方,但我已经经历了一百万次这对我来说很好看。

这是我的优先队列类:

package lab3;

import java.util.ArrayList;

/**
 * A priority queue class supporting operations needed for
 * Dijkstra's algorithm.
 */

class PriorityQueue<T> {

final static int INF = 1000000000;
ArrayList<PQNode<T>> queue;

/**
 * Constructor
 */
public PriorityQueue() {
    queue = new ArrayList<PQNode<T>>();
}

/**
 * @return true iff the queue is empty.
 */
public boolean isEmpty() {
    if (queue.size() <= 0)
        return true;
    return false;
}

/**
 * Insert a (key, value) pair into the queue.
 *
 * @return a Handle to this pair so that we can find it later.
 */
Handle insert(int key, T value) {
    queue.add(new PQNode(key, value));    

    int loc = queue.size()-1;
    // Swap with parent until parent not larger
    while (loc > 0 && queue.get(loc).getKey() < queue.get(parent(loc)).getKey()) {
        swap(loc, parent(loc));
        loc = parent(loc);
    }
    return new Handle(loc);
}

private void swap(int i, int j) {
    PQNode t = queue.get(i);

    queue.set(i, queue.get(j));
    queue.get(i).setHandleIndex(i);

    queue.set(j, t);
    queue.get(j).setHandleIndex(j);
}


/**
 * @return the min key in the queue.
 */
public int min() {
    if (isEmpty())
        return -INF;
    return queue.get(0).getKey();
}

/**
 * Find and remove the smallest (key, value) pair in the queue.
 *
 * @return the value associated with the smallest key
 */

public T extractMin() {
    if (isEmpty())
        return null;
    else{
        T value = queue.get(0).getValue();
        swap(0, queue.size()-1);
        queue.get(queue.size()-1).setHandleIndex(-1);
        queue.remove(queue.size()-1);
        heapify(0);
        return value;
    }
}



private void heapify(int i) {
    int left = leftChild(i);
    int right = rightChild(i);
    int min;

    if (left <= queue.size()-1 && queue.get(left).getKey() < queue.get(i).getKey())
        min = left;
    else
        min = i;
    if (right <= queue.size()-1 && queue.get(right).getKey() < queue.get(min).getKey())
        min = right;
    if (min != i){
        swap(i, min);
        heapify(min);
    }
}
private static int parent(int i) {
    return (i-1)/2;
}

private static int leftChild(int i) {
    return 2*i + 1;
}

   /**
 * @return the key associated with the Handle.
 */
public int handleGetKey(Handle h) {
    if (h.getIndex() >= 0)
        return queue.get(h.getIndex()).getKey();
    return -INF;
}


/**
 * Decrease the key to the newKey associated with the Handle.
 *
 * If the pair is no longer in the queue, or if its key <= newKey,
 * do nothing and return false.  Otherwise, replace the key with newkey,
 * fix the ordering of the queue, and return true.
 *
 * @return true if we decreased the key, false otherwise.
 */
public boolean decreaseKey(Handle h, int newKey){
    if (h.getIndex() == -1) //negative 1 is my signal for an invalidated handle
        return false;
    if (newKey > queue.get(h.getIndex()).getKey())
        return false;
    queue.get(h.getIndex()).setKey(newKey); // set the new key
    correct(h.index);       // restore the min-heap property
    return true;
}
public void correct(int i)
{
    {
        while (i > 0 && queue.get(parent(i)).getKey() > queue.get(i).getKey()) {
            swap(i, parent(i));
            i = parent(i);
        }
    }   
}



/**
 * Return the index of the right child of node i.
 * @param i index of parent
 * @return the index of the right child of node i
 */
private static int rightChild(int i) {
    return 2*i + 2;
}

/**
     * @return the value associated with the Handle.
     */
public T handleGetValue(Handle h) {
        if (h.getIndex() >= 0){
            return queue.get(h.getIndex()).getValue();}
        else{
            return null;
            }
    }

我的PQNode课程:

package lab3;

public class PQNode<T> {

int key;
T value;
Handle handle;

PQNode(int k, T v){
    key = k;
    value = v;
    handle = new Handle(0);
}

/**
 * @return the key
 */
public int getKey() {
    return key;
}

/**
 * @param key the key to set
 */
public void setKey(int key) {
    this.key = key;
}

/**
 * @return the value
 */
public T getValue() {
    return value;
}

/**
 * @param value the value to set
 */
public void setValue(T value) {
    this.value = value;
}

public void setHandle(Handle handle){
    this.handle = handle;
}

/**
 * @return the handle
 */
public Handle getHandle() {
    return handle;
}
public int getHandleIndex(){
    return handle.getIndex();
}
public void setHandleIndex(int i){
    handle.setIndex(i);
}
}

我的手柄类:

package lab3;

public class Handle {

int index;


public Handle(int i) {
    index = i;
}

/**
 * @return the index
 */
public int getIndex() {
    return index;
}

/**
 * @param index the index to set
 */
public void setIndex(int index) {
    this.index = index;
}
}

因为这是学校的工作,我会很感激提示,但尽量不要脱口而出。另外,如果您愿意,我也可以发布测试,但我不知道这是否会带来很多好处。只知道队列应该按原样运行,但是在使用extractMin()之后句柄不指向正确的节点。如果您想了解更多信息,请告诉我,我知道这有点模糊。非常感谢你们。

编辑:这是我失败的特殊测试

 public void basicHandleAndDecreaseTest() {
        PriorityQueue<String> q = new PriorityQueue<String>();
        Map<String, Handle> valuesToHandles = new HashMap<String, Handle>();
        Map<String, Integer> valuesToKeys = new HashMap<String, Integer>();
        int seq = 0;
        // Generate random numbres for the keys.
        for (int i = 0; i < 20; i++) {
            int key = RAND.nextInt(100);
            String val = Integer.toString(seq); // guarantees that the value is unique.
            seq++;
            valuesToKeys.put(val, key);
        }
        // Keep track of handles and build queue.
        for (Map.Entry<String, Integer> entry : valuesToKeys.entrySet()) {
            int key = entry.getValue();
            String value = entry.getKey();
            Handle h = q.insert(key, value);
            assertEquals(key, q.handleGetKey(h));
            assertEquals(value, q.handleGetValue(h));

            valuesToHandles.put(value, h);
        }

        // Remove some of the elements.
        for (int i = 0; i < 5; i++) {
            String val = q.extractMin();
            valuesToKeys.remove(val);
            valuesToHandles.remove(val);
        }
        // Make sure the handles are still valid.
        for (Map.Entry<String, Integer> entry : valuesToKeys.entrySet()) {
            int key = entry.getValue();
            String value = entry.getKey();
            Handle h = valuesToHandles.get(value);
            assertEquals(value, q.handleGetValue(h));  <--Here is when I fail

        }

        // Add some more elements.
        int limit = seq + 5;
        for (int i = seq; i < limit; i++) {
            int key = RAND.nextInt(100);
            String val = Integer.toString(seq);
            seq++;
            valuesToKeys.put(val, key);
            Handle h = q.insert(key, val);
            valuesToHandles.put(val, h);
        }

        // Decrease keys unnecessarily and verify that they still work.
        for (Map.Entry<String, Integer> entry : valuesToKeys.entrySet()) {
            int key = entry.getValue();
            String value = entry.getKey();
            Handle h = valuesToHandles.get(value);
            q.decreaseKey(h, key + 1);
            assertEquals(key, q.handleGetKey(h));
            assertEquals(value, q.handleGetValue(h));
        }

        // Change keys randomly, and check that the values remain attached to handles.
        for (Map.Entry<String, Integer> entry : valuesToKeys.entrySet()) {
            int key = entry.getValue();
            String value = entry.getKey();
            Handle h = valuesToHandles.get(value);
            int newKey = RAND.nextInt(100);
            q.decreaseKey(h, newKey);
            if (newKey < key) {
                assertEquals(newKey, q.handleGetKey(h));
            } else {
                assertEquals(key, q.handleGetKey(h));
            }
            assertEquals(value, q.handleGetValue(h));
        }
    }

1 个答案:

答案 0 :(得分:0)

如果没有脱口而出,插入时返回的句柄应该是刚刚插入的节点的句柄,而不是新节点。这样,当你进行交换时它会得到更新。节点的句柄也需要初始化为比零更相关的东西。

这会让你接下来的错误......

  1. 测试程序中的一个错误,标记为“不必要地减少密钥并验证它们是否仍然有效”。正在测试错误的“密钥”值。节点中的密钥已更改为key+1,,因此应该进行测试,而不是key.这同样适用于标记为“随机更改密钥,并检查值是否仍附加到句柄”的块,只有这次新密钥是随机的,而不是key+1.

  2. decreaseKey()的意思使我失望。