2017-05-07 92 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'的設計是一個壞主意,它只是爲了記住它在隊列中的順序。如果你想同時添加'訂單'在兩個不同的隊列,在每個隊列中有不同的位置?這就是爲什麼我在答案中提出了額外的課程。 –