6

我已经为优先级队列定义了自己的比较函数,但是比较函数需要数组的信息。问题是当数组的值发生变化时,并没有影响比较功能。我该如何处理?代码示例:

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;

public class Main {
    public static final int INF = 100;
    public static int[] F = new int[201];

    public static void main(String[] args){

        PriorityQueue<Integer> Q = new PriorityQueue<Integer>(201, 
            new Comparator<Integer>(){
                public int compare(Integer a, Integer b){
                    if (F[a] > F[b]) return 1;
                    if (F[a] == F[b]) return 0;
                    return -1;
                }
            });

            Arrays.fill(F, INF);
            F[0] = 0; F[1] = 1; F[2] = 2;
            for (int i = 0; i < 201; i ++) Q.add(i);
            System.out.println(Q.peek()); // Prints 0, because F[0] is the smallest
            F[0] = 10;
            System.out.println(Q.peek()); // Still prints 0 ... OMG
        }
   }
4

3 回答 3

4

您的比较器仅在您修改队列时(即添加项目时)才会被调用。在那之后,队列不知道有什么东西导致了顺序改变,这就是为什么它保持不变。

有一个像这样的比较器是相当令人困惑的。如果你有两个值,A 和 B,并且在某个时候 A>B,每个人都会期望 A 保持大于 B。我认为你对这个问题使用优先级队列是错误的。

于 2013-02-06T20:44:55.260 回答
3

因此,本质上,您正在动态更改比较标准,而这不是优先队列合同提供的功能。请注意,这似乎适用于某些情况(例如,在删除或插入另一个项目时,堆可能会对某些项目进行排序),但由于您无法保证,这不是一种有效的方法。

您可以做的是,每次更改数组时,都将所有元素取出,然后将它们放回原处。这当然非常昂贵( O(n*log(n))),因此您可能应该尝试工作围绕您的设计,以避免更改数组值。

于 2013-02-06T20:44:49.950 回答
2

使用在 peek 上使用比较器的 PriorityQueue 的自定义实现,而不是在 add 上:

public class VolatilePriorityQueue <T> extends AbstractQueue <T>
{
    private final Comparator <? super T> comparator;

    private final List <T> elements = new ArrayList <T> ();

    public VolatilePriorityQueue (Comparator <? super T> comparator)
    {
        this.comparator = comparator;
    }

    @Override
    public boolean offer (T e)
    {
        return elements.add (e);
    }

    @Override
    public T poll ()
    {
        if (elements.isEmpty ()) return null;
        else return elements.remove (getMinimumIndex ());
    }

    @Override
    public T peek ()
    {
        if (elements.isEmpty ()) return null;
        else return elements.get (getMinimumIndex ());
    }

    @Override
    public Iterator <T> iterator ()
    {
        return elements.iterator ();
    }

    @Override
    public int size ()
    {
        return elements.size ();
    }

    private int getMinimumIndex ()
    {
        T e = elements.get (0);
        int index = 0;

        for (int count = elements.size (), i = 1; i < count; i++)
        {
            T ee = elements.get (i);
            if (comparator.compare (e, ee) > 0)
            {
                e = ee;
                index = i;
            }
        }

        return index;
    }
}
于 2013-02-06T20:52:15.243 回答