2017-05-07 54 views
7

在我的PriorityQueue中,我有2种类型的客户,VIP和常规。我想先服务VIP,然后定期。Java PriorityQueue自定义比较器

如果客户ID为< 100它被认为是VIP。

如果客户是贵宾,他去在队列

的VIP部分结束时如果客户是有规律的,他去在整个队列的末尾。

换句话说,我想布尔VIP值进行排序,同时保留在客户前来顺序

这里是我的Order类

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 

这是我希望看到(客户ID 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任何其他列排序想要的。我不想添加“日期”,因为它感觉像是一个黑客,而不是理解Java如何工作。

+0

您的compareTo不比较数额,以及它必须这样做才能成功。 –

+1

将最后一次返回值从'return 0;'更改为'return Integer.compare(amount,o.amount);' –

+1

@HovercraftFullOfEels OP希望订单成为插入队列的顺序,并且数量似乎只是无关的数据。 – RealSkeptic

回答

4

看来,PriorityQueue类,开箱即用的感觉可以自由地重新排列项目,如果他们比较相等,彼此

(这不是“的java是如何工作的”,它只是代表自带的Java运行时某一类有点变态)

所以,这里的东西,可能会工作:

  1. 引入一个新的OrderPlacement类,含有a)一种Order和b)int priority

  2. 在您的PriorityQueue中添加OrderPlacement对象而不是Order对象。

  3. 当您创建一个新的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); 
} 
+0

那么,如果你颠倒了顺序('返回-Boolean.compare(...'),那么它会更接近你需要的东西,但仍然不是那样,这就是为什么我修改了我的答案。 –

+0

看起来像你如果他们相互比较,java可以自由地重新排序项目“,请在你的回答中强调一下吗? –

+0

@VladimirS。sure,done –

2

如果必须做使用优先级队列它,下面的代码将解决你的问题。请注意,我正在使用静态计数器来维护具有相同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的

+0

通过引入一个额外的字段来污染'Order'的设计是一个坏主意,它只是为了记住它在队列中的顺序。如果你想同时添加'订单'在两个不同的队列,在每个队列中有不同的位置?这就是为什么我在答案中提出了额外的课程。 –