优先队列在算法设计中的应用

优先队列在算法设计中的应用

大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!

优先队列概述

优先队列是一种特殊的队列数据结构,每个元素都有一个优先级。与普通队列不同的是,在优先队列中,具有较高优先级的元素会被优先处理。优先队列主要通过堆(heap)来实现,常见的实现方式有最大堆和最小堆。

  • 最大堆:每个节点的值都不小于其子节点的值,堆顶元素是最大值。
  • 最小堆:每个节点的值都不大于其子节点的值,堆顶元素是最小值。

优先队列的基本操作

  1. 插入元素:将新元素添加到优先队列中,并保持堆的性质。
  2. 删除最大/最小元素:删除堆顶元素(最大堆删除最大值,最小堆删除最小值),并重新调整堆以保持堆的性质。
  3. 查看堆顶元素:返回当前优先队列中优先级最高(最小)的元素,但不删除它。

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* 搜索算法。通过优先队列,我们可以有效地处理和优化这些算法中的关键操作,提高计算效率和性能。

本文著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值