数据结构与算法 - 寻路算法

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快!

引言

寻路算法是计算机科学中一个重要的主题,用于在图中寻找从起点到终点的最短路径。这类算法广泛应用于游戏开发、地图导航、网络路由等领域。本文将深入探讨几种常见的寻路算法,包括 Dijkstra 算法和 A* 算法,并通过具体的 Java 代码详细说明它们的实现步骤。

一、寻路算法概述

寻路算法通常基于图论,其中图由节点(顶点)和边组成。节点代表地图中的位置,而边则表示节点间的连接。寻路算法的目标是从起点到终点找到一条路径,这条路径通常是成本最低的(例如距离最短或代价最小)。

二、Dijkstra 算法

Dijkstra 算法是一种用于解决单源最短路径问题的贪心算法。它保证找到从一个特定的起点到图中所有其他节点的最短路径。

1. Dijkstra 算法步骤
  1. 初始化:设置起点的距离为 0,其余节点的距离为无穷大。
  2. 选择未访问的最近节点:从未访问的节点中选择距离最短的节点。
  3. 更新邻居:更新所选节点的邻居的距离,如果通过当前节点到达邻居的距离更短,则更新邻居的距离。
  4. 标记已访问:将所选节点标记为已访问。
  5. 重复步骤 2 至 4,直到所有节点都被访问过或找到了目标节点。
2. Java 实现

首先,定义图节点和边的类:

import java.util.*;

class GraphNode {
    int id;
    String label;
    Map<GraphNode, Integer> neighbors;

    public GraphNode(int id, String label) {
        this.id = id;
        this.label = label;
        this.neighbors = new HashMap<>();
    }

    public void addNeighbor(GraphNode neighbor, int weight) {
        neighbors.put(neighbor, weight);
    }

    public void removeNeighbor(GraphNode neighbor) {
        neighbors.remove(neighbor);
    }
}

class Graph {
    private Map<Integer, GraphNode> nodes;

    public Graph() {
        nodes = new HashMap<>();
    }

    public void addNode(GraphNode node) {
        nodes.put(node.id, node);
    }

    public void removeNode(GraphNode node) {
        nodes.remove(node.id);
        // Remove references to this node from its neighbors
        for (GraphNode neighbor : node.neighbors.keySet()) {
            neighbor.removeNeighbor(node);
        }
    }

    public void addEdge(GraphNode node1, GraphNode node2, int weight) {
        node1.addNeighbor(node2, weight);
        node2.addNeighbor(node1, weight);  // For undirected graph
    }

    public void removeEdge(GraphNode node1, GraphNode node2) {
        node1.removeNeighbor(node2);
        node2.removeNeighbor(node1);  // For undirected graph
    }

    public void dijkstra(GraphNode start) {
        PriorityQueue<GraphNode> queue = new PriorityQueue<>(Comparator.comparingInt(n -> n.distance));
        Map<GraphNode, Integer> distances = new HashMap<>();
        Map<GraphNode, GraphNode> previous = new HashMap<>();

        for (GraphNode node : nodes.values()) {
            if (node == start) {
                distances.put(node, 0);
            } else {
                distances.put(node, Integer.MAX_VALUE);
            }
            queue.offer(node);
        }

        while (!queue.isEmpty()) {
            GraphNode current = queue.poll();

            for (Map.Entry<GraphNode, Integer> entry : current.neighbors.entrySet()) {
                GraphNode neighbor = entry.getKey();
                int weight = entry.getValue();
                int distanceThroughCurrent = distances.get(current) + weight;

                if (distanceThroughCurrent < distances.get(neighbor)) {
                    distances.put(neighbor, distanceThroughCurrent);
                    previous.put(neighbor, current);
                    queue.remove(neighbor);
                    queue.offer(neighbor);
                }
            }
        }

        printPath(previous, start, nodes.get(3));  // Example: Print path to node with ID 3
    }

    private void printPath(Map<GraphNode, GraphNode> previous, GraphNode start, GraphNode end) {
        List<GraphNode> path = new ArrayList<>();
        for (GraphNode node = end; node != null; node = previous.get(node)) {
            path.add(node);
        }
        Collections.reverse(path);

        System.out.print("Shortest path from " + start.label + " to " + end.label + ": ");
        for (GraphNode node : path) {
            System.out.print(node.label + " ");
        }
        System.out.println();
    }
}
3. Java 示例代码

创建图并执行 Dijkstra 算法:

public class Main {
    public static void main(String[] args) {
        Graph graph = new Graph();

        // 创建节点
        GraphNode nodeA = new GraphNode(1, "A");
        GraphNode nodeB = new GraphNode(2, "B");
        GraphNode nodeC = new GraphNode(3, "C");
        GraphNode nodeD = new GraphNode(4, "D");
        GraphNode nodeE = new GraphNode(5, "E");

        // 添加节点到图
        graph.addNode(nodeA);
        graph.addNode(nodeB);
        graph.addNode(nodeC);
        graph.addNode(nodeD);
        graph.addNode(nodeE);

        // 添加边
        graph.addEdge(nodeA, nodeB, 7);
        graph.addEdge(nodeA, nodeD, 5);
        graph.addEdge(nodeB, nodeC, 8);
        graph.addEdge(nodeB, nodeD, 9);
        graph.addEdge(nodeB, nodeE, 7);
        graph.addEdge(nodeC, nodeE, 5);
        graph.addEdge(nodeD, nodeE, 15);
        graph.addEdge(nodeD, nodeC, 15);
        graph.addEdge(nodeE, nodeC, 2);

        // 执行 Dijkstra 算法
        graph.dijkstra(nodeA);
    }
}

三、A* 算法

A* 算法是一种启发式搜索算法,它结合了 Dijkstra 算法和启发式函数的优势。A* 算法利用启发式函数来估计从当前节点到目标节点的近似成本,从而更快地找到最优路径。

1. A* 算法步骤
  1. 初始化:设置起点的 f 值(g 值 + h 值),其余节点的 f 值为无穷大。
  2. 选择未访问的最近节点:从未访问的节点中选择 f 值最小的节点。
  3. 更新邻居:更新所选节点的邻居的 g 值和 f 值,如果通过当前节点到达邻居的成本更低,则更新邻居的成本。
  4. 标记已访问:将所选节点标记为已访问。
  5. 重复步骤 2 至 4,直到所有节点都被访问过或找到了目标节点。
2. Java 实现
import java.util.*;

class AStarNode extends GraphNode {
    int g;  // Cost from start to this node
    int h;  // Estimated cost from this node to goal
    int f;  // Total estimated cost: g + h
    AStarNode previous;

    public AStarNode(int id, String label) {
        super(id, label);
        this.g = Integer.MAX_VALUE;
        this.h = 0;
        this.f = Integer.MAX_VALUE;
        this.previous = null;
    }

    public void setHeuristic(int heuristic) {
        this.h = heuristic;
        this.f = g + h;
    }
}

class AStarGraph extends Graph {
    public void aStar(AStarNode start, AStarNode goal) {
        PriorityQueue<AStarNode> openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
        Set<AStarNode> closedSet = new HashSet<>();

        start.g = 0;
        start.setHeuristic(estimateCost(start, goal));
        openSet.add(start);

        while (!openSet.isEmpty()) {
            AStarNode current = openSet.poll();

            if (current.equals(goal)) {
                printPath(current);
                return;
            }

            closedSet.add(current);

            for (AStarNode neighbor : current.neighbors.keySet()) {
                if (closedSet.contains(neighbor)) {
                    continue;
                }

                int tentativeGScore = current.g + current.neighbors.get(neighbor);
                if (tentativeGScore < neighbor.g) {
                    neighbor.previous = current;
                    neighbor.g = tentativeGScore;
                    neighbor.setHeuristic(estimateCost(neighbor, goal));
                    if (!openSet.contains(neighbor)) {
                        openSet.add(neighbor);
                    }
                }
            }
        }
    }

    private void printPath(AStarNode node) {
        List<AStarNode> path = new ArrayList<>();
        while (node != null) {
            path.add(node);
            node = node.previous;
        }
        Collections.reverse(path);

        System.out.print("Shortest path found: ");
        for (AStarNode n : path) {
            System.out.print(n.label + " ");
        }
        System.out.println();
    }

    private int estimateCost(AStarNode start, AStarNode goal) {
        // Simple heuristic: Manhattan distance
        return Math.abs(start.id - goal.id);
    }
}
3. Java 示例代码

创建图并执行 A* 算法:

public class Main {
    public static void main(String[] args) {
        AStarGraph graph = new AStarGraph();

        // 创建节点
        AStarNode nodeA = new AStarNode(1, "A");
        AStarNode nodeB = new AStarNode(2, "B");
        AStarNode nodeC = new AStarNode(3, "C");
        AStarNode nodeD = new AStarNode(4, "D");
        AStarNode nodeE = new AStarNode(5, "E");

        // 添加节点到图
        graph.addNode(nodeA);
        graph.addNode(nodeB);
        graph.addNode(nodeC);
        graph.addNode(nodeD);
        graph.addNode(nodeE);

        // 添加边
        graph.addEdge(nodeA, nodeB, 7);
        graph.addEdge(nodeA, nodeD, 5);
        graph.addEdge(nodeB, nodeC, 8);
        graph.addEdge(nodeB, nodeD, 9);
        graph.addEdge(nodeB, nodeE, 7);
        graph.addEdge(nodeC, nodeE, 5);
        graph.addEdge(nodeD, nodeE, 15);
        graph.addEdge(nodeD, nodeC, 15);
        graph.addEdge(nodeE, nodeC, 2);

        // 执行 A* 算法
        graph.aStar(nodeA, nodeE);
    }
}

四、总结

寻路算法是计算机科学中一个重要的领域,尤其适用于需要寻找最优路径的应用场景。在实际编程中,寻路算法可以用于解决各种问题,例如在游戏开发中实现 NPC 寻路、地图导航软件中规划路线等。


💝💝💝如有需要请大家订阅我的专栏【数据结构与算法】哟!我会定期更新相关系列的文章
💝💝💝关注!关注!!请关注!!!请大家关注下博主,您的支持是我不断创作的最大动力!!!

数据结构与算法相关文章索引文章链接
数据结构与算法-插入排序数据结构与算法-插入排序
数据结构与算法-希尔排序数据结构与算法-希尔排序
数据结构与算法-归并排序数据结构与算法-归并排序
数据结构与算法-随机快速排序数据结构与算法-随机快速排序
数据结构与算法-双路快速排序数据结构与算法-双路快速排序
数据结构与算法-三路排序数据结构与算法-三路排序
数据结构与算法-关于堆的基本存储介绍数据结构与算法-关于堆的基本存储介绍
数据结构与算法-关于堆的基本排序介绍数据结构与算法-关于堆的基本排序介绍
数据结构与算法-索引堆及其优化数据结构与算法-索引堆及其优化
数据结构与算法-二分搜索树数据结构与算法-二分搜索树
数据结构与算法-二分搜索树链表节点的插入数据结构与算法-二分搜索树链表节点的插入
数据结构与算法-二分搜索树节点的查找数据结构与算法-二分搜索树节点的查找
数据结构与算法-二分搜索树遍历数据结构与算法-二分搜索树遍历
数据结构与算法-二分搜索树层序遍历数据结构与算法-二分搜索树层序遍历
数据结构与算法-二分搜索树节点删除历数据结构与算法-二分搜索树节点删除
数据结构 - 并查集基础数据结构 - 并查集基础
数据结构 - 并查集 size 的优化 数据结构 - 并查集 size 的优化
数据结构 - 并查集 rank 的优化 数据结构 - 并查集 rank 的优化
数据结构 - 并查集路径压缩 数据结构 - 并查集路径压缩
数据结构 - 图论基础 数据结构 - 图论基础
数据结构 - 相邻节点迭代器 数据结构 - 相邻节点迭代器

❤️❤️❤️觉得有用的话点个赞 👍🏻 呗。
❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄
💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍
🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

  • 33
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟小码

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值