翻译自callicoder
Java中的优先队列是一种特殊类型的队列,其中所有的元素在创建时都以其自然序或者提供的自定义的比较器Comparator
排序。
优先队列的队头包含最小序的元素(根据指定的排序规则),而队尾包含最大序的元素。
因此,当你从优先级队列中删除元素时,根据指定排序规则的最小元素会首先被移除。
创建一个优先队列
这里创建一个整数型的优先队列并且添加一些元素进去。添加完后,我们一个个移除元素,看出队元素的顺序。
import java.util.PriorityQueue;
public class CreatePriorityQueueExample {
public static void main(String[] args) {
// 创建一个优先队列
PriorityQueue<Integer> numbers = new PriorityQueue<>();
// 把元素添加进优先队列 (入队)
numbers.add(750);
numbers.add(500);
numbers.add(900);
numbers.add(100);
// 从优先队列中一处元素(出队)
while (!numbers.isEmpty()) {
System.out.println(numbers.remove());
}
}
}
输出:
100
500
750
900
再看一个String类型的优先队列:
import java.util.PriorityQueue;
public class CreatePriorityQueueStringExample {
public static void main(String[] args) {
// Create a Priority Queue
PriorityQueue<String> namePriorityQueue = new PriorityQueue<>();
// Add items to a Priority Queue (ENQUEUE)
namePriorityQueue.add("Lisa");
namePriorityQueue.add("Robert");
namePriorityQueue.add("John");
namePriorityQueue.add("Chris");
namePriorityQueue.add("Angelina");
namePriorityQueue.add("Joe");
// Remove items from the Priority Queue (DEQUEUE)
while (!namePriorityQueue.isEmpty()) {
System.out.println(namePriorityQueue.remove());
}
}
}
输出:
Angelina
Chris
Joe
John
Lisa
Robert
可以看到,String类型优先队列安字典序出队。
用自定义比较器Comparator
创建一个优先队列
我们假设需要一个String类型的优先队列,但要根据字符串长度从小到大排序。
我们可以通过提供一个比较字符串长度的Comparator
来创建优先队列。
import java.util.Comparator;
import java.util.PriorityQueue;
public class PriorityQueueCustomComparatorExample {
public static void main(String[] args) {
// 一个自定义的comparator,根据字符串长度比较
Comparator<String> stringLengthComparator = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
};
/*
上边的Comparator 也可以用lambda表达式来实现 =>
Comparator<String> stringLengthComparator = (s1, s2) -> {
return s1.length() - s2.length();
};
或者可以更精简如下 =>
Comparator<String> stringLengthComparator = Comparator.comparingInt(String::length);
*/
// Create a Priority Queue with a custom Comparator
PriorityQueue<String> namePriorityQueue = new PriorityQueue<>(stringLengthComparator);
// Add items to a Priority Queue (ENQUEUE)
namePriorityQueue.add("Lisa");
namePriorityQueue.add("Robert");
namePriorityQueue.add("John");
namePriorityQueue.add("Chris");
namePriorityQueue.add("Angelina");
namePriorityQueue.add("Joe");
// Remove items from the Priority Queue (DEQUEUE)
while (!namePriorityQueue.isEmpty()) {
System.out.println(namePriorityQueue.remove());
}
}
}
输出:
Joe
John
Lisa
Chris
Robert
Angelina
注意长度最小的字符串优先出队。
用户自定义对象的优先队列
在下面的例子中,你可以学习如何创建用户自定义对象的优先队列。
因着优先队列需要对元素进行排序,用户自定的类必须要实现Comparable
接口,或者再创建优先队列时必须提供一个Comparator
对象。否则,当插入元素是,会报出ClassCastException
异常。
看下面的例子,我们创建了一个承装自定义类Employee
的优先队列。Employee
类实现了Comparable
接口,比较员工的薪水。
import java.util.Objects;
import java.util.PriorityQueue;
class Employee implements Comparable<Employee> {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
//set get方法省略
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, salary);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
// 根据薪水比较员工
@Override
public int compareTo(Employee employee) {
if(this.getSalary() > employee.getSalary()) {
return 1;
} else if (this.getSalary() < employee.getSalary()) {
return -1;
} else {
return 0;
}
}
}
public class PriorityQueueUserDefinedObjectExample {
public static void main(String[] args) {
/*
创建自定义类的优先队列的需求是:
1. 类需要实现Comparable接口,实现其compareTo方法。
2. 或者创建时提供一个Comparator。
*/
// Create a PriorityQueue
PriorityQueue<Employee> employeePriorityQueue = new PriorityQueue<>();
// Add items to the Priority Queue
employeePriorityQueue.add(new Employee("Rajeev", 100000.00));
employeePriorityQueue.add(new Employee("Chris", 145000.00));
employeePriorityQueue.add(new Employee("Andrea", 115000.00));
employeePriorityQueue.add(new Employee("Jack", 167000.00));
/*
出队的顺序是由Employee类中实现的compareTo()方法决定的。
*/
while (!employeePriorityQueue.isEmpty()) {
System.out.println(employeePriorityQueue.remove());
}
}
}
输出:
Employee{name=‘Rajeev’, salary=100000.0}
Employee{name=‘Andrea’, salary=115000.0}
Employee{name=‘Chris’, salary=145000.0}
Employee{name=‘Jack’, salary=167000.0}
注意,薪水最低的员工优先出队。
结论
通过这篇文章,你学到了
- 什么是优先队列
- 如何使用自定义比较器的优先队列
- 如何使用自定义类的优先队列