为一系列具有较高优先级的元素和其他具有较低优先级的元素排序优先级队列

Posted

技术标签:

【中文标题】为一系列具有较高优先级的元素和其他具有较低优先级的元素排序优先级队列【英文标题】:Sorting priority queue for a range of elements with higher priority and other elements with lower priority 【发布时间】:2017-08-30 04:57:47 【问题描述】:

我有一个包含以下字段的实体类:id、orderNo。每个 实体必须存储在 java 优先级队列中。元素 id 在 1 - 3000 之间的具有更高的优先级,必须存储在 在 id > 3000 的元素之上 orderNo 的升序。 元素 ids > 3000 以 orderNo 的升序存储在下面 更高优先级的元素(ids 1 - 3000)。

例如:

(1st insertion to queue: id=4000 orderNo=1) 
(2nd insertion to queue: id=5000 orderNo=2) 
(3rd insertion to queue: id=100  orderNo=3)
(4th insertion to queue: id=50   orderNo=4)

预期的排序顺序:

(id=100  orderNo=3) 
(id=50   orderNo=4) 
(id=4000 orderNo=1) 
(id=5000 orderNo=2)

OrderEntity 类:

public class OrderEntity implements Comparable<OrderEntity> 
    private int id;
    private int getOrderNo;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public int getOrderNo() 
        return getOrderNo;
    

    public void setOrderNo(int getOrderNo) 
        this.getOrderNo = getOrderNo;
    

    @Override
    public int compareTo(OrderEntity arg0) 
        if ((this.getId() >= 1 && this.getId() <= 3000) && (arg0.getId() >= 1 && arg0.getId() <= 3000)) 
            if (this.getOrderNo() > arg0.getOrderNo()) 
                return 1;
             else 
                return 0;
            
         else if ((this.getId() <= 3000) && (arg0.getId() > 3000)) 
            return 1;
         else if ((this.getId() > 3000) && (arg0.getId() <= 3000)) 
            return 1;
         else if ((this.getId() > 3000) && (arg0.getId() > 3000)) 
            if (this.getOrderNo() > arg0.getOrderNo()) 
                return 1;
             else 
                return 0;
            
         else 
            return 0;
        
    

OrderProcessor 类:

public class OrderProcessor 
    private static int count;
    static Queue<OrderEntity> pq = new PriorityQueue<>();

    public String createOrder(int id) 
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setId(id);
        count = count + 1;
        orderEntity.setOrderNo(count);
        pq.add(orderEntity);

        String res = "";
        for (OrderEntity rd : pq) 
            res = res + rd.getId() + " " + rd.getOrderNo() + "\n";
        
        return res.trim();
    

【问题讨论】:

你的问题是......? 我的问题是我无法通过上述实现获得这个序列。想知道我哪里出错了。 一个问题是您的compareTo 方法,如果第一项不大于第二项,则返回0(表示相等)。 compareTo 应返回 -1、0 或 1,具体取决于第一项小于、等于还是大于第二项。通常,您使用Integer.compare 来检查。 【参考方案1】:

在这种情况下,对象的自然顺序与您的特殊要求不同,最好不要使用Comparable,因为它将来可能会有其他用途。所以,剩下的解决方案是使用Comparator,它非常适合你的问题,因为你的OrderEntity 类不会依赖这个特殊的比较。以下是显示解决方案的示例代码:

import java.util.Comparator;
import java.util.PriorityQueue;

public class OrderProcessor 
    public static void main(String[] args) 
        PriorityQueue<OrderEntity> q = new PriorityQueue<>(new OrderEntityComparator());
        q.add(new OrderEntity(4000, 1));
        q.add(new OrderEntity(5000, 2));
        q.add(new OrderEntity(100, 3));
        q.add(new OrderEntity(50, 4));

        while(!q.isEmpty())
            System.out.println(q.poll());
    

    public static class OrderEntityComparator implements Comparator<OrderEntity> 

        @Override
        public int compare(OrderEntity o1, OrderEntity o2) 
            if(o1.getId() <= 3000 && o2.getId() <= 3000)
                return Integer.compare(o1.getOrderNo(), o2.getOrderNo());
            if(o1.getId() > 3000 && o2.getId() > 3000)
                return Integer.compare(o1.getOrderNo(), o2.getOrderNo());
            if(o1.getId() <= 3000 && o2.getId() > 3000)
                return -1;
            return 1;
        
    

    public static class OrderEntity 
        private int id;
        private int orderNo;

        public OrderEntity(int id, int orderNo) 
            this.id = id;
            this.orderNo = orderNo;
        

        public int getId() 
            return id;
        

        public void setId(int id) 
            this.id = id;
        

        public int getOrderNo() 
            return orderNo;
        

        public void setOrderNo(int orderNo) 
            this.orderNo = orderNo;
        

        @Override
        public String toString() 
            return "OrderEntity" +
                    "id=" + id +
                    ", orderNo=" + orderNo +
                    '';
        
    

编辑:

如果您不想通过调用poll 方法删除元素,则必须将元素排序到数组或列表中,如下所示:

    OrderEntity[] a = new OrderEntity[q.size()];
    q.toArray(a);
    Arrays.sort(a, new OrderEntityComparator());

    for(OrderEntity entity : a)
        System.out.println(entity);

事实上,在这种情况下,您不需要使用 PriorityQueue,只需对 List 或数组进行简单排序即可。

【讨论】:

不工作。尝试使用以下输入:(100,1) (200,2) (4000,3) (300,4)。预期输出:(100,1) (200,2) (300,4) (4000,3)。实际输出:(100,1) (200,2) (4000,3) (300,4) @AshwinShirva 您的预期输出是什么?我的输出是:(100,1) (200,2) (300,4) (4000,3) @AshwinShirva 我运行了代码,输出与您预期的相同。请检查我的代码好吗? @MehdiJavan 我接受了您对问题的建议编辑,并进行了我自己的小幅编辑:) 它可以工作,正如你提到的那样,在 while 循环中使用 poll()。一个简单的问题,有没有办法在不使用 poll() 的情况下按顺序遍历优先级队列元素?因为我不想修改原来的队列。我只想检索值(按顺序)。【参考方案2】:

这是一个使用 Java 8 的解决方案,不需要任何复杂的比较器实现。我针对您提供的两个示例运行它。诀窍是要意识到有 2 组 id,那些

public class Main 
    private static Comparator<OrderEntity> orderEntityComparator =
        Comparator.<OrderEntity, Integer>comparing(OrderEntity::getId,
                comparingInt(id -> id / 3000)
        )
                .thenComparingInt(OrderEntity::getOrderNo);

    public static void main(String[] args) 
        PriorityQueue<OrderEntity> queue = new PriorityQueue<>(orderEntityComparator);
        queue.add(new OrderEntity(4000, 1));
        queue.add(new OrderEntity(5000, 2));
        queue.add(new OrderEntity(100, 3));
        queue.add(new OrderEntity(50, 4));

        // 100, 50, 4000, 5000

        queue.clear();

        queue.add(new OrderEntity(100, 1));
        queue.add(new OrderEntity(200, 2));
        queue.add(new OrderEntity(4000, 3));
        queue.add(new OrderEntity(300, 4));

        while (!queue.isEmpty()) 
            System.out.println(queue.poll());
        
        // 100, 200, 300, 4000
    

    static class OrderEntity 
        private int id;
        private int orderNo;

        public OrderEntity(int id, int orderNo) 
            this.id = id;
            this.orderNo = orderNo;
        

        public int getId() 
            return id;
        

        public int getOrderNo() 
            return orderNo;
        

        @Override
        public String toString() 
            return String.format("(id=%d, orderNo=%d)", id, orderNo);
        
    

【讨论】:

以上是关于为一系列具有较高优先级的元素和其他具有较低优先级的元素排序优先级队列的主要内容,如果未能解决你的问题,请参考以下文章

Java 运算符优先级

运算符优先级

JavaScript中运算符的优先级

js中运算符的优先级

JS之运算符的优先级

JavaScript中运算符的优先级