为什么我需要可比较的PriorityQueue?

时间:2018-05-16 11:31:30

标签: java list collections queue comparable

我正在学习队列收集,我不明白为什么在使用PriorityQueue时我需要实现Comparable接口?我在数组/列表的自定义排序中使用了Comparable和Comparator接口。但是,当我不想对它进行排序时,为什么我需要为PriorityQueue实现...

在下面的示例中,如果我没有实现Comparable接口,我发现我无法在PriorityQueue中添加元素。

对我来说很大的误解,在我运行此代码之后,列表没有按ID排序?我问这个问题因为我看到compareTo()方法被覆盖了,当我想对列表进行排序时我使用这个方法。

我记得当我为列表完成自定义排序时,我已经使用了exaclty这段代码。列表按id排序。为什么队列在这种情况下没有排序?

抱歉我的英语语法。任何反馈都会被贬低!

import java.util.PriorityQueue;
import java.util.Queue;

    public class QueueExample {

        public static void main(String[] args) { 

            Queue<Book> queue = new PriorityQueue<>();

            //Creating Books  
            Book b1=new Book(121,"Let us C","Yashwant Kanetkar","BPB",8);  
            Book b2=new Book(233,"Operating System","Galvin","Wiley",6);  
            Book b3=new Book(101,"Data Communications & Networking","Forouzan","Mc Graw Hill",4); 
            Book b4=new Book(319,"Learn Java","Yanis Orhan","HEX",3);  
            Book b5=new Book(191,"Linux","Hadgy","Haman",7);  
            Book b6=new Book(287,"Python Programming","Tarzan","GEN",5); 

            //Adding Books to the queue  
            queue.add(b1);  
            queue.add(b2);  
            queue.add(b3);  
            queue.add(b4);  
            queue.add(b5);  
            queue.add(b6); 

            System.out.println("Traversing the queue elements:");  

            //Traversing queue elements  
            for(Book b : queue) {  

                System.out.println(b.id+" "+b.name+" "+b.author+" "+b.publisher+" "+b.quantity);  
            }  

            queue.remove();  
            System.out.println("After removing one book record:");  
            for(Book b : queue) { 

                System.out.println(b.id + " " + b.name + " " + b.author + " " + b.publisher + " " + b.quantity);  
            }  
        }  
    }

public class Book implements Comparable<Book> {

    int id;  
    String name,author,publisher;  
    int quantity;  

    public Book(int id, String name, String author, String publisher, int quantity) {

        this.id = id;  
        this.name = name;  
        this.author = author;  
        this.publisher = publisher;  
        this.quantity = quantity;  
    }

    @Override
    public int compareTo(Book b) {

        if(id > b.id) {  

            return 1;  
        } else if (id < b.id) {  

            return -1;  
        } else {  

            return 0;  
        }
    }    
}

我看到头部是id最低的元素,但之后没有顺序。为什么队列没有按ID排序?

Traversing the queue elements:
101 Data Communications & Networking Forouzan Mc Graw Hill 4
191 Linux Hadgy Haman 7
121 Let us C Yashwant Kanetkar BPB 8
319 Learn Java Yanis Orhan HEX 3
233 Operating System Galvin Wiley 6
287 Python Programming Tarzan GEN 5
After removing one book record:
121 Let us C Yashwant Kanetkar BPB 8
191 Linux Hadgy Haman 7
287 Python Programming Tarzan GEN 5
319 Learn Java Yanis Orhan HEX 3
233 Operating System Galvin Wiley 6

更新

如果我创建一个ArrayList并使用相同的compareTo()方法对其进行排序,并使用相同的for-each循环打印它,则会对列表进行排序并按此顺序打印。

ArrayList的代码:

import java.util.ArrayList;
import java.util.Collections;

public class BookExample {

    public static void main(String args[]) {

            ArrayList<Book> bookList = new ArrayList<>();

            Book b1=new Book(121,"Let us C","Yashwant Kanetkar","BPB",8);  
            Book b2=new Book(233,"Operating System","Galvin","Wiley",6);  
            Book b3=new Book(101,"Data Communications & Networking","Forouzan","Mc Graw Hill",4); 
            Book b4=new Book(319,"Learn Java","Yanis Orhan","HEX",3);  
            Book b5=new Book(191,"Linux","Hadgy","Haman",7);  
            Book b6=new Book(287,"Python Programming","Tarzan","GEN",5); 

            bookList.add(b1);  
            bookList.add(b2);  
            bookList.add(b3);  
            bookList.add(b4);  
            bookList.add(b5);  
            bookList.add(b6); 

            Collections.sort(bookList);

            for (Book b : bookList) {

              System.out.println(b.id + ", " + b.name + ", " + b.author + ", " 
              + b.publisher + ", " + b.quantity);
            }
          }
}

public class Book implements Comparable<Book> {

    int id;  
    String name, author, publisher;  
    int quantity;  

      public Book(int id, String name, String author, String publisher, int quantity) {

        this.id = id;
        this.name = name;
        this.author = author;  
        this.publisher = publisher;  
        this.quantity = quantity;  
      }


    public int compareTo(Book b) {

            if(id > b.id) {  

                return 1;  
            } else if (id < b.id) {  

                return -1;  
            } else {  

                return 0;  
            }
      }
}

控制台中的结果:

101, Data Communications & Networking, Forouzan, Mc Graw Hill, 4
121, Let us C, Yashwant Kanetkar, BPB, 8
191, Linux, Hadgy, Haman, 7
233, Operating System, Galvin, Wiley, 6
287, Python Programming, Tarzan, GEN, 5
319, Learn Java, Yanis Orhan, HEX, 3

为什么打印ArrayList时for-each循环工作得非常好,当我尝试打印PriorityQueue时它不起作用?

4 个答案:

答案 0 :(得分:5)

Javadoc says

  

方法iterator()中提供的迭代器无法保证以任何特定顺序遍历优先级队列的元素。如果您需要有序遍历,请考虑使用Arrays.sort(pq.toArray())

因此,您不能只使用for(Book book: queue)循环。

您可以按照Javadoc中的建议复制到临时数组中,或者(如果您不介意在此过程中销毁队列)循环遍历poll()

我同意这是违反直觉的。他们可能根本不应该实现Iterable ......

答案 1 :(得分:0)

PriorityQueue用于特定目的:允许您从队列中获取最高“优先级”项目,而不管其添加顺序如何。您提供的比较仅用于确定“优先级”。在订单中迭代的意义上,它不是一个有序的集合。

您可以依次删除项目并进行比较来测试。您会发现删除它们的顺序是由您定义的比较定义的。

答案 2 :(得分:0)

PriorityQueuejavadoc

  

基于优先级堆的无界优先级队列。优先级队列的元素根据其自然顺序排序,或者由队列构造时提供的比较器排序,具体取决于使用的构造函数。优先级队列不允许null元素。依赖于自然排序的优先级队列也不允许插入不可比较的对象(这样做可能会导致ClassCastException)。

在将新元素添加到队列时,需要一种比较元素的方法,以便正确地确定元素的优先级。

要按顺序打印队列,您需要使用以下建议:

  

如果需要有序遍历,请考虑使用Arrays.sort(pq.toArray())。

P / S:我想你只想在java中实现Queue接口,然后突然跳转到PriorityQueue

在这种情况下,ArrayDeque<>最符合您的需求。

答案 3 :(得分:-1)

List和PriorityQueue之间的区别在于,List通过插入来保持元素的排序,而另一方面,PriorityQueue会根据您的情况(ID)按照您希望的属性来排序元素。如果您要插入的元素无法相互比较,则PriorityQueue行为默认为列表的行为。