Java PriorityQueue 自定义比较器
Java PriorityQueue custom Comparator
在我的 PriorityQueue 中,我有 2 种类型的客户,VIP 和普通客户。我想先服务VIP,再服务普通。
如果 CustomerID < 100 则被视为 VIP。
如果客户是 VIP,他会排在 VIP 队列的末尾
如果顾客是常客,他会排在整个队列的末尾。
换句话说,我想按布尔 VIP 值排序,同时保留客户进来的顺序。
这是我的订单class
public class Order implements Comparable<Order> {
private final int customerID;
private final int amount;
private final boolean vip_status;
public Order(int customerID, int amount) {
this.customerID = customerID;
this.amount = amount;
this.vip_status = customerID < 100 ? true : false;
}
@Override
public int compareTo(Order o) {
if (vip_status && !o.vip_status) {
return -1;
}
if (!vip_status && o.vip_status)
return 1;
return 0;
}
public int getCustomerID() {
return customerID;
}
public int getAmount() {
return amount;
}
public boolean isVip_status() {
return vip_status;
}
}
这是我尝试填充队列的尝试:
import java.util.PriorityQueue;
public class MyPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Order> queue = new PriorityQueue<>();
Order o1 = new Order(1, 50);
Order o2 = new Order(5, 30);
Order o3 = new Order(4, 10);
Order o4 = new Order(150, 5);
Order o5 = new Order(2, 5);
Order o6 = new Order(200, 5);
queue.add(o1);
queue.add(o2);
queue.add(o3);
queue.add(o4);
queue.add(o5);
queue.add(o6);
while(!queue.isEmpty()){
Order s = queue.poll();
System.out.printf("VIP Status: %s CustomerID: %s Amount: %s%n",
s.isVip_status(), s.getCustomerID(), s.getAmount());
}
}
}
我得到的结果(错误):
VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5
这是我希望看到的(CustomerID 2 和 4 的顺序应该与它们进来的顺序相同):
VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5
更新:除了 VIP,我不想按任何其他列排序。我不想添加 "date" 因为它感觉像是一个 hack,而不是理解 Java 是如何工作的。
看来 java 随附的 PriorityQueue
class 如果它们相互比较相等,可以随意重新订购商品.
(这不是"how java works",只是对Java Runtime自带的某个class的一点歪曲。)
所以,这里可能会起作用:
引入新的 OrderPlacement
class,包含 a) Order
和 b) int priority
.
在您的 PriorityQueue
中添加 OrderPlacement
个对象而不是 Order
个对象。
当您创建一个新的 OrderPlacement
对象时,通过递增计数器为其发出一个新的 priority
。
然后,您的 OrderPlacement
对象可以有一个 compareTo()
方法,如下所示:
@Override
public int compareTo( OrderPlacement o )
{
int d = -Boolean.compare( order.vip_status, o.order.vip_status );
if( d != 0 )
return d;
return Integer.compare( priority, o.priority );
}
如果您必须使用优先级队列,下面的代码将解决您的问题。请注意,我使用静态计数器来维护具有相同 VIP 状态的元素的正确顺序,因为相等的元素在优先级队列中以随机顺序维护。这是因为优先级队列使用最小/最大堆数据结构,它只关心将最小/最大元素放在堆顶部而不关心相同元素的排序。
import java.util.PriorityQueue;
public class Order implements Comparable<Order> {
private final int customerID;
private final int amount;
private final int vip_status;
private final int score;
private static int counter = 0;
public Order(int customerID, int amount) {
this.customerID = customerID;
this.amount = amount;
this.vip_status = customerID < 100 ? 0 : 1;
this.score = counter++;
}
@Override
public String toString() {
return customerID + " : " + amount + " : " + vip_status;
}
@Override
public int compareTo(Order o) {
int status = ((Integer) this.vip_status).compareTo(o.vip_status);
status = status == 0 ? ((Integer) this.score).compareTo(o.score) : status;
return status;
}
public static void main(String[] args) {
Order o1 = new Order(1000, 100);
Order o2 = new Order(500, 100);
Order o3 = new Order(99, 100);
Order o4 = new Order(10, 100);
Order o5 = new Order(200, 100);
Order o6 = new Order(1, 100);
PriorityQueue<Order> orderQueue = new PriorityQueue<>();
orderQueue.offer(o1);
orderQueue.offer(o2);
orderQueue.offer(o3);
orderQueue.offer(o4);
orderQueue.offer(o5);
orderQueue.offer(o6);
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
}
}
`
示例输出:
99 : 100 : 0
10 : 100 : 0
1 : 100 : 0
1000 : 100 : 1
500 : 100 : 1
200 : 100 : 1
注意:您需要注意分数最终可能达到Integer.MAX_VALUE
在我的 PriorityQueue 中,我有 2 种类型的客户,VIP 和普通客户。我想先服务VIP,再服务普通。
如果 CustomerID < 100 则被视为 VIP。
如果客户是 VIP,他会排在 VIP 队列的末尾
如果顾客是常客,他会排在整个队列的末尾。
换句话说,我想按布尔 VIP 值排序,同时保留客户进来的顺序。
这是我的订单class
public class Order implements Comparable<Order> {
private final int customerID;
private final int amount;
private final boolean vip_status;
public Order(int customerID, int amount) {
this.customerID = customerID;
this.amount = amount;
this.vip_status = customerID < 100 ? true : false;
}
@Override
public int compareTo(Order o) {
if (vip_status && !o.vip_status) {
return -1;
}
if (!vip_status && o.vip_status)
return 1;
return 0;
}
public int getCustomerID() {
return customerID;
}
public int getAmount() {
return amount;
}
public boolean isVip_status() {
return vip_status;
}
}
这是我尝试填充队列的尝试:
import java.util.PriorityQueue;
public class MyPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Order> queue = new PriorityQueue<>();
Order o1 = new Order(1, 50);
Order o2 = new Order(5, 30);
Order o3 = new Order(4, 10);
Order o4 = new Order(150, 5);
Order o5 = new Order(2, 5);
Order o6 = new Order(200, 5);
queue.add(o1);
queue.add(o2);
queue.add(o3);
queue.add(o4);
queue.add(o5);
queue.add(o6);
while(!queue.isEmpty()){
Order s = queue.poll();
System.out.printf("VIP Status: %s CustomerID: %s Amount: %s%n",
s.isVip_status(), s.getCustomerID(), s.getAmount());
}
}
}
我得到的结果(错误):
VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5
这是我希望看到的(CustomerID 2 和 4 的顺序应该与它们进来的顺序相同):
VIP Status: true CustomerID: 1 Amount: 50
VIP Status: true CustomerID: 5 Amount: 30
VIP Status: true CustomerID: 4 Amount: 10
VIP Status: true CustomerID: 2 Amount: 5
VIP Status: false CustomerID: 150 Amount: 5
VIP Status: false CustomerID: 200 Amount: 5
更新:除了 VIP,我不想按任何其他列排序。我不想添加 "date" 因为它感觉像是一个 hack,而不是理解 Java 是如何工作的。
看来 java 随附的 PriorityQueue
class 如果它们相互比较相等,可以随意重新订购商品.
(这不是"how java works",只是对Java Runtime自带的某个class的一点歪曲。)
所以,这里可能会起作用:
引入新的
OrderPlacement
class,包含 a)Order
和 b)int priority
.在您的
PriorityQueue
中添加OrderPlacement
个对象而不是Order
个对象。当您创建一个新的
OrderPlacement
对象时,通过递增计数器为其发出一个新的priority
。
然后,您的 OrderPlacement
对象可以有一个 compareTo()
方法,如下所示:
@Override
public int compareTo( OrderPlacement o )
{
int d = -Boolean.compare( order.vip_status, o.order.vip_status );
if( d != 0 )
return d;
return Integer.compare( priority, o.priority );
}
如果您必须使用优先级队列,下面的代码将解决您的问题。请注意,我使用静态计数器来维护具有相同 VIP 状态的元素的正确顺序,因为相等的元素在优先级队列中以随机顺序维护。这是因为优先级队列使用最小/最大堆数据结构,它只关心将最小/最大元素放在堆顶部而不关心相同元素的排序。
import java.util.PriorityQueue;
public class Order implements Comparable<Order> {
private final int customerID;
private final int amount;
private final int vip_status;
private final int score;
private static int counter = 0;
public Order(int customerID, int amount) {
this.customerID = customerID;
this.amount = amount;
this.vip_status = customerID < 100 ? 0 : 1;
this.score = counter++;
}
@Override
public String toString() {
return customerID + " : " + amount + " : " + vip_status;
}
@Override
public int compareTo(Order o) {
int status = ((Integer) this.vip_status).compareTo(o.vip_status);
status = status == 0 ? ((Integer) this.score).compareTo(o.score) : status;
return status;
}
public static void main(String[] args) {
Order o1 = new Order(1000, 100);
Order o2 = new Order(500, 100);
Order o3 = new Order(99, 100);
Order o4 = new Order(10, 100);
Order o5 = new Order(200, 100);
Order o6 = new Order(1, 100);
PriorityQueue<Order> orderQueue = new PriorityQueue<>();
orderQueue.offer(o1);
orderQueue.offer(o2);
orderQueue.offer(o3);
orderQueue.offer(o4);
orderQueue.offer(o5);
orderQueue.offer(o6);
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
System.out.println(orderQueue.poll());
}
}
`
示例输出:
99 : 100 : 0
10 : 100 : 0
1 : 100 : 0
1000 : 100 : 1
500 : 100 : 1
200 : 100 : 1
注意:您需要注意分数最终可能达到Integer.MAX_VALUE