Пользовательский компаратор Java PriorityQueue


В моем PriorityQueue у меня есть 2 типа клиентов, VIP и регулярные. Я хочу сначала обслуживать VIP, а потом обычных клиентов.

Если CustomerID

Если клиент VIP, он идет в конце VIP-части очереди

Если клиент является постоянным, он идет в конце всей очереди.

Другими словами, Я хочу Сортировать по логическому значению VIP, сохраняя при этом порядок поступления клиентов.

Вот мой заказ. класс

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

UPDATE: я не хочу Сортировать по любому другому столбцу, кроме VIP. Я не хочу добавлять "дату", потому что это похоже на взлом, а не на понимание того, как работает Java.

2 8

2 ответа:

Похоже, что класс PriorityQueue, с которым java поставляется из коробки, чувствует себя свободно переупорядочивать элементы, если они сравниваются как равные друг другу .

(это не "как работает java", это просто небольшое извращение от имени определенного класса, который поставляется с Java Runtime.)

Итак, вот что, вероятно, сработает:

  1. Введем новый класс OrderPlacement, содержащий a) an Order и b) an 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 );
}

Если вы должны сделать это с помощью очереди приоритетов, приведенный ниже код решит вашу проблему. Обратите внимание, что я использую статический счетчик для поддержания правильного порядка элементов с одинаковым VIP-статусом, поскольку равные элементы поддерживаются в случайном порядке внутри приоритетной очереди. Это происходит потому, что приоритетная очередь использует структуру данных кучи min / max, и она заботится только о размещении элемента min / max в верхней части кучи и не беспокоится о порядке одних и тех же элементов.

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

Примечание: Вы должны знать, что оценка может в конечном итоге достичь целого числа.Массив