在Java中与任何比较器一起使用PriorityQueue
常见问题:如何使用自定义类的不同比较器对PriorityQueue中的对象进行排序 我尝试在适当的优先级队列对中使用此比较器,并在下一个代码中使用具有类似排序结果的对象列表:在Java中与任何比较器一起使用PriorityQueue,java,Java,常见问题:如何使用自定义类的不同比较器对PriorityQueue中的对象进行排序 我尝试在适当的优先级队列对中使用此比较器,并在下一个代码中使用具有类似排序结果的对象列表: class User{ private Integer id; private String name; public User(Integer i, String n){ this.id=i; this.name=n; } public Integer getId() {return
class User{
private Integer id;
private String name;
public User(Integer i, String n){
this.id=i;
this.name=n;
}
public Integer getId() {return id;}
public String getName() {return name;}
@Override
public boolean equals(Object obj) {
if (this == obj)return true;
if (obj == null)return false;
if (getClass() != obj.getClass())return false;
User other = (User) obj;
if(id == null){
if (other.id != null)return false;
}else if(!id.equals(other.id))return false;
return true;
}
@Override
public String toString() {return "[id:" + id + ", name:" + name + "]";}
}
public class MyPriorityQueue {
public static Comparator<User> cmpId = Comparator.comparingInt(x -> x.getId());
public static Comparator<User> cmpNameLength = Comparator.comparingInt(x -> x.getName().length());
public static void main(String[] args) {
List<User> users = new ArrayList<User>(10);
users.add(new User(1,"11111"));
users.add(new User(3,"333"));
users.add(new User(5,"5"));
users.add(new User(4,"44"));
users.add(new User(2,"2222"));
Queue<User> ids = new PriorityQueue<User>(10, cmpId); //use first comparator
users.forEach(x-> ids.offer(x));
Queue<User> names = new PriorityQueue<User>(10, cmpNameLength); //use second comparator
names.addAll(users);
System.out.println("Variant_1.1:");
ids.forEach(System.out::println);
System.out.println("Variant_2.1:");
names.forEach(System.out::println);
System.out.println("Variant_1.2:");
users.sort(cmpId); //use first comparator
users.forEach(System.out::println);
System.out.println("Variant_2.2:");
users.sort(cmpNameLength); //use second comparator
users.forEach(System.out::println);
}
}
我希望:
- 变量1.1和2.1的结果李>
- 变量1.2和2.2的结果李>
我的问题:我在排序priorityqueue/comparator时犯了什么错误?在我的示例中,如何获得priorityqueue的排序结果以及相应的列表?在您的代码示例中,您使用它来迭代队列
ids.forEach(System.out::println);
names.forEach(System.out::println);
forEach
最终委托到。但是,需要注意的是,中的子类override有不同的javadoc,其中有一个关于排序的特殊注释
返回此队列中元素的迭代器。迭代器不会以任何特定顺序返回元素
换句话说,不能保证在PriorityQueue
上迭代将使用比较器。相反,如果您通过反复调用来更改代码以耗尽队列,那么我希望您会看到根据自定义比较器排序的结果
深入研究OpenJDK源代码,我们可以看到其中的内部数据结构是一个。这是由一个数组支持的,当调用方添加和删除队列元素时,代码在内部保持堆不变
/**
* Priority queue represented as a balanced binary heap: the two
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
* priority queue is ordered by comparator, or by the elements'
* natural ordering, if comparator is null: For each node n in the
* heap and each descendant d of n, n <= d. The element with the
* lowest value is in queue[0], assuming the queue is nonempty.
*/
transient Object[] queue; // non-private to simplify nested class access
您没有做错什么,只是PriorityQueue
的迭代器是:
不保证以任何特定顺序遍历优先级队列的元素()
forEach的forEach
方法在内部使用迭代器,因此也存在同样的问题
这是因为底层的数据结构是这样的,它可以在您定义项时“排序”。如果实现者希望按排序的顺序返回项目,他们必须首先收集项目,然后在返回之前对其进行排序。这会导致性能下降,因此(我猜想)决定无序返回,因为PriorityQueue
主要是一个队列,而不是一个排序的集合,用户可以自己对项目进行排序(这是最有效的)
要获得有序的元素,请执行以下操作:
while(pq.peek() != null){
System.out.println(pq.poll());
}
感谢您澄清“forEach”。在更正代码“while(!ids.isEmpty())System.out.println(ids.poll());”而不是“ids.forEach(System.out::println);”之后,获得了预期的结果。
return (E) queue[lastRet = cursor++];
while(pq.peek() != null){
System.out.println(pq.poll());
}