Java深入了解数据结构之优先级队列(堆)
本文将会详细介绍Java中的优先级队列,即堆数据结构的实现过程和使用方法。
什么是优先级队列?
在介绍优先级队列之前,我们需要了解先进先出队列(FIFO Queue)和后进先出队列(LIFO Queue,或称栈)的概念。FIFO Queue按照元素的插入顺序依次出队;而LIFO Queue则按照元素的插入顺序反向出队。而优先级队列则按照元素的权重大小出队,越小的权重越优先出队。例如,对于任务队列,有些任务是紧急的,需要最先执行,而有些任务则可以拖延时间,优先级队列就能够帮助我们实现这个需求。
优先级队列可以用各种各样的数据结构实现,包括有序数组、无序数组、链表、二叉搜索树、哈希表等。其中,最常用的实现方式是堆。
堆数据结构
堆可以看成是一颗完全二叉树(Complete Binary Tree),即除了最后一层的节点,其它层次的节点都是满的。并且最后一层的所有节点都必须靠左排列。堆中每个节点都有一个值,一般是一个数字,且满足以下两个条件:
- 父节点的值总是大于或等于(小于或等于)任何一个子节点的值。
- 每个节点的左右子树都是一个堆。
我们称满足条件1的堆为大根堆,满足条件2的堆为堆。
堆的插入和删除操作都会导致堆的结构发生变化,因此需要维护堆的性质,使其成为一个合法的堆。
优先级队列的实现
Java标准库中提供了优先级队列 PriorityQueue 类。下面我们通过示例代码来了解如何使用 PriorityQueue 类来实现优先级队列。
示例1:基本实现
import java.util.PriorityQueue;
public class PriorityQueueDemo1 {
public static void main(String[] args) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.add(5);
queue.add(3);
queue.add(1);
queue.add(4);
queue.add(2);
while(!queue.isEmpty()) {
System.out.println(queue.poll());
}
}
}
上述示例中,我们先创建一个 PriorityQueue
示例2:定制元素的比较方法
有时候,我们需要使用自己定义的元素类型,并且这个类型不支持自然比较,我们可以通过实现 Comparator 接口来定义该类型的比较方法。示例代码如下:
import java.util.Comparator;
import java.util.PriorityQueue;
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class PointComparator implements Comparator<Point> {
@Override
public int compare(Point p1, Point p2) {
int dis1 = p1.x * p1.x + p1.y * p1.y;
int dis2 = p2.x * p2.x + p2.y * p2.y;
return dis1 - dis2;
}
}
public class PriorityQueueDemo2 {
public static void main(String[] args) {
PriorityQueue<Point> queue = new PriorityQueue<>(new PointComparator());
queue.add(new Point(3, 4));
queue.add(new Point(1, 2));
queue.add(new Point(5, 6));
queue.add(new Point(7, 8));
queue.add(new Point(0, 0));
while(!queue.isEmpty()) {
Point p = queue.poll();
System.out.println("(" + p.x + "," + p.y + ")");
}
}
}
在上述示例中,我们先定义一个 Point 类,然后定义一个 PointComparator 类,重写其中的 compare 方法。这个方法用于计算两个 Point 对象的距离,以便可以进行比较。在创建 PriorityQueue 对象时,我们将自定义的 Comparator 作为参数传入。在添加元素时,PriorityQueue 会使用这个 Comparator 进行比较并保证队列元素的顺序。
总结
以上就是Java中实现优先级队列的方法以及 PriorityQueue 类的应用方法。需要注意的是,PriorityQueue 类默认会以自然顺序(按元素的自然顺序进行比较)排序元素。如果不在创建对象时指定 Comparator,则必须确保元素类型支持自然比较。
同时也注意到,由于堆的数据结构特殊性,其实现更加繁琐,数据结构本身难以调试,因此需要了解并掌握其概念才能够更加熟练地使用 PriorityQueue 类。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java深入了解数据结构之优先级队列(堆) - Python技术站