我试图用自定义比较器实现带有Priorityqueue的MST,但是我在O(n)时间内用它构建min-heap时遇到了问题。问题是,Priorityqueue的一个构造函数只允许在O(n)中创建PriorityQueue,但它不会将任何比较器作为参数。我希望它使用我的自定义比较器。这个问题有解决方法吗? PriorityQueue.addAll()将失去使用Min-heap作为MST的目的,因为它是O(nlogn)方法。这是我的代码。
ArrayList <edge>ar=new ArrayList<>();
for(int i=0;i<e;i++)
{
int u=ss.nextInt();
int v=ss.nextInt();
int w=ss.nextInt();
ar.add(new edge(u,v,w));
}
PriorityQueue <edge>pr=new PriorityQueue<edge>(ar);
我要使用的比较器: -
PriorityQueue <edge>ar=new PriorityQueue(11,new Comparator() {
@Override
public int compare(Object o1, Object o2) {
edge n1=(edge) o1;
edge n2=(edge) o2;
if(n1.w<n2.w)
{
return -1;
}
else if(n1.w==n2.w)
{
if((n1.u+n1.v+n1.w)<=(n2.u+n2.v+n2.w))
{
return -1;
}
else
{
return 1;
}
}
else
{
return 1;
}
}
});
答案 0 :(得分:3)
如果你没有在其他地方对你的列表进行最小堆排序,你将无法new PriorityQueue(...)
任何东西,并以某种方式避免创建堆的命中。数学here表示平均情况为O(n)
,但它不仅仅是迭代。
PriorityQueue<edge> pr = new PriorityQueue<edge>(ar, comp) {
PriorityQueue(List<edge> ar, Comparator<edge> c) {
this(c);
for(int i = 0; i < queue.length; i++) {
queue[i] = ar.get(i);
}
this.size = queue.length;
heapify(); // O(n), except that heapify is private and thus you can't call it!!!
}
}
现在我还没有对此进行过测试,它只是在我的头顶,有一些来自PriorityQueue源的指导,但它应该指向正确的方向。
但是有时候你必须支付piper并创建堆顺序,这不仅仅是迭代。但是,由于O(n)
,它仍然应该在heapify
上。
另一个选择是edge
实施Comparable<edge>
。然后你可以PriorityQueue<edge> pr = new PriorityQueue(ar);
如果您无法控制edge implements Comparable<edge>
,那么您可以撰写容器类:
class EdgeContainer implements Comparable<EdgeContainer> {
private static final Comparator<edge> comp = ; // that comparator above
private final edge edge;
EdgeContainer(Edge edge) { this.edge = edge; }
public int compareTo(EdgeContainer e) { return comp.compare(edge, e.edge); }
public edge getEdge() { return edge; }
}
List <EdgeContainer>ar=new ArrayList<>();
for(int i=0;i<e;i++)
{
int u=ss.nextInt();
int v=ss.nextInt();
int w=ss.nextInt();
ar.add(new EdgeContainer(new edge(u,v,w)));
}
PriorityQueue<EdgeContainer> qr = new PriorityQueue(ar);
答案 1 :(得分:2)
Java PriorityQueue
花费O(n)时间从传递给它的集合中创建优先级队列。 CLSR第6.4章(第3版第157页)给出了数学证明。直观地说,当底层数组使用siftDown
或siftUp
变为堆时,下一个sift
操作循环的元素数量的大小也会减小,从而导致O (n)时间复杂性。
但正如评论中所讨论的那样,正如您在问题中提到的那样,使用addAll()
无法实现这种时间复杂性。原因是adAll()
继承自AbstractQueue
,并且通过将集合中的元素逐个添加到队列中来工作,这可能导致O(nlogn)时间复杂度。
因此,如果O(n)时间复杂度是绝对要求,则除了为集合中包含的对象类实现Comparator
接口之外别无选择。 @ corsiKa的回答很好地详述了这种方法。另请注意,即使您将集合直接传递给PriorityQueue
,它也会将其转换为基本上是另一个O(n)操作的数组。