优先队列在算法设计中的应用
大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!
优先队列概述
优先队列是一种特殊的队列数据结构,每个元素都有一个优先级。与普通队列不同的是,在优先队列中,具有较高优先级的元素会被优先处理。优先队列主要通过堆(heap)来实现,常见的实现方式有最大堆和最小堆。
- 最大堆:每个节点的值都不小于其子节点的值,堆顶元素是最大值。
- 最小堆:每个节点的值都不大于其子节点的值,堆顶元素是最小值。
优先队列的基本操作
- 插入元素:将新元素添加到优先队列中,并保持堆的性质。
- 删除最大/最小元素:删除堆顶元素(最大堆删除最大值,最小堆删除最小值),并重新调整堆以保持堆的性质。
- 查看堆顶元素:返回当前优先队列中优先级最高(最小)的元素,但不删除它。
Java中的优先队列实现
在 Java 中,PriorityQueue
类提供了优先队列的实现。PriorityQueue
默认使用最小堆实现,但可以通过传递自定义比较器来实现最大堆。
使用 Java PriorityQueue
实现最大堆
package cn.juwatech.priorityqueue;
import java.util.PriorityQueue;
import java.util.Comparator;
public class MaxHeapExample {
public static void main(String[] args) {
// 创建一个最大堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
// 插入元素
maxHeap.add(10);
maxHeap.add(20);
maxHeap.add(5);
maxHeap.add(15);
// 打印并删除元素
while (!maxHeap.isEmpty()) {
System.out.println(maxHeap.poll());
}
}
}
代码解释
- 使用
Comparator.reverseOrder()
创建一个最大堆。 - 插入元素到优先队列中。
- 使用
poll()
方法删除并打印堆顶元素。
应用实例:Dijkstra算法
Dijkstra 算法用于计算单源最短路径,特别适用于图中边的权重为非负值的情况。优先队列在 Dijkstra 算法中用于选择当前路径最短的节点,从而高效地更新其他节点的最短路径。
Dijkstra 算法实现
package cn.juwatech.graph;
import java.util.*;
public class DijkstraAlgorithm {
static class Graph {
private final Map<Integer, List<Edge>> adjList = new HashMap<>();
void addEdge(int source, int destination, int weight) {
adjList.computeIfAbsent(source, k -> new ArrayList<>()).add(new Edge(destination, weight));
adjList.computeIfAbsent(destination, k -> new ArrayList<>()).add(new Edge(source, weight));
}
List<Edge> getEdges(int node) {
return adjList.getOrDefault(node, new ArrayList<>());
}
}
static class Edge {
int destination;
int weight;
Edge(int destination, int weight) {
this.destination = destination;
this.weight = weight;
}
}
public static Map<Integer, Integer> dijkstra(Graph graph, int start) {
Map<Integer, Integer> distances = new HashMap<>();
PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));
// Initialize distances
for (int node : graph.adjList.keySet()) {
distances.put(node, Integer.MAX_VALUE);
}
distances.put(start, 0);
minHeap.add(new AbstractMap.SimpleEntry<>(start, 0));
while (!minHeap.isEmpty()) {
Map.Entry<Integer, Integer> entry = minHeap.poll();
int current = entry.getKey();
int currentDistance = entry.getValue();
if (currentDistance > distances.get(current)) {
continue;
}
for (Edge edge : graph.getEdges(current)) {
int newDistance = currentDistance + edge.weight;
if (newDistance < distances.get(edge.destination)) {
distances.put(edge.destination, newDistance);
minHeap.add(new AbstractMap.SimpleEntry<>(edge.destination, newDistance));
}
}
}
return distances;
}
public static void main(String[] args) {
Graph graph = new Graph();
graph.addEdge(1, 2, 1);
graph.addEdge(1, 3, 4);
graph.addEdge(2, 3, 2);
graph.addEdge(2, 4, 5);
graph.addEdge(3, 4, 1);
Map<Integer, Integer> distances = dijkstra(graph, 1);
for (Map.Entry<Integer, Integer> entry : distances.entrySet()) {
System.out.println("Distance from 1 to " + entry.getKey() + " is " + entry.getValue());
}
}
}
代码解释
- 图的表示:使用邻接表表示图,每个节点的邻接边存储在
Graph
类中。 - Dijkstra 算法:初始化所有节点的距离为无穷大,起点的距离为0。使用优先队列选择当前最短路径的节点,并更新其邻居的距离。
应用实例:A*搜索算法
A* 搜索算法用于路径规划,尤其在地图和导航应用中非常有用。它结合了 Dijkstra 算法的优点和贪心算法的启发式方法,优先考虑目标方向。
A 算法实现*
package cn.juwatech.graph;
import java.util.*;
public class AStarAlgorithm {
static class Graph {
private final Map<Integer, List<Edge>> adjList = new HashMap<>();
private final Map<Integer, int[]> heuristics = new HashMap<>();
void addEdge(int source, int destination, int weight) {
adjList.computeIfAbsent(source, k -> new ArrayList<>()).add(new Edge(destination, weight));
}
void setHeuristic(int node, int heuristic) {
heuristics.put(node, new int[]{heuristic});
}
List<Edge> getEdges(int node) {
return adjList.getOrDefault(node, new ArrayList<>());
}
int getHeuristic(int node) {
return heuristics.getOrDefault(node, new int[]{0})[0];
}
}
static class Edge {
int destination;
int weight;
Edge(int destination, int weight) {
this.destination = destination;
this.weight = weight;
}
}
public static Map<Integer, Integer> aStar(Graph graph, int start, int goal) {
Map<Integer, Integer> gScore = new HashMap<>();
Map<Integer, Integer> fScore = new HashMap<>();
PriorityQueue<Map.Entry<Integer, Integer>> openSet = new PriorityQueue<>(Comparator.comparingInt(Map.Entry::getValue));
Set<Integer> closedSet = new HashSet<>();
gScore.put(start, 0);
fScore.put(start, graph.getHeuristic(start));
openSet.add(new AbstractMap.SimpleEntry<>(start, fScore.get(start)));
while (!openSet.isEmpty()) {
Map.Entry<Integer, Integer> currentEntry = openSet.poll();
int current = currentEntry.getKey();
if (current == goal) {
return gScore;
}
closedSet.add(current);
for (Edge edge : graph.getEdges(current)) {
if (closedSet.contains(edge.destination)) {
continue;
}
int tentativeGScore = gScore.getOrDefault(current, Integer.MAX_VALUE) + edge.weight;
if (tentativeGScore < gScore.getOrDefault(edge.destination, Integer.MAX_VALUE)) {
gScore.put(edge.destination, tentativeGScore);
int fScoreValue = tentativeGScore + graph.getHeuristic(edge.destination);
fScore.put(edge.destination, fScoreValue);
openSet.add(new AbstractMap.SimpleEntry<>(edge.destination, fScoreValue));
}
}
}
return Collections.emptyMap();
}
public static void main(String[] args) {
Graph graph = new Graph();
graph.addEdge(1, 2, 1);
graph.addEdge(1, 3, 4);
graph.addEdge(2, 3, 2);
graph.addEdge(2, 4, 5);
graph.addEdge(3, 4, 1);
graph.setHeuristic(1, 7);
graph.setHeuristic(2, 6);
graph.setHeuristic(3, 2);
graph.setHeuristic(4, 0);
Map<Integer, Integer> distances = aStar(graph, 1, 4);
for (Map.Entry<Integer, Integer> entry : distances.entrySet()) {
System.out.println("Distance from 1 to " + entry.getKey() + " is " + entry.getValue());
}
}
}
代码解释
- 图的表示:图的表示与 Dijkstra 算法
相似,但添加了启发式函数。
- A 算法*:结合了实际成本(
gScore
)和启发式成本(fScore
),优先处理估计总成本最低的节点。
总结
优先队列是一种强大的数据结构,在许多算法中发挥了重要作用,如 Dijkstra 算法和 A* 搜索算法。通过优先队列,我们可以有效地处理和优化这些算法中的关键操作,提高计算效率和性能。
本文著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!