导读:本期聚焦于小伙伴创作的《C#如何实现A Star算法?C#中A*寻路算法的完整实现步骤是什么》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何实现A Star算法?C#中A*寻路算法的完整实现步骤是什么》有用,将其分享出去将是对创作者最好的鼓励。

A*寻路算法结合了Dijkstra算法的广度优先特性和贪心算法的最优性,通过评估函数f(n)=g(n)+h(n)选择最优路径节点,其中g(n)是从起点到当前节点的实际代价,h(n)是当前节点到终点的预估代价,在C#中实现该算法需要按照固定流程处理节点和路径逻辑。

C#如何实现A Star算法?C#中A*寻路算法的完整实现步骤是什么

A*算法核心概念

实现前需要先明确几个核心概念,避免逻辑混淆:

  • 节点(Node):地图中的最小单元,通常对应网格的一个格子,包含位置、代价、父节点等属性
  • 开放列表(Open List):存储待检查的节点,每次从中选取f值最小的节点进行扩展
  • 关闭列表(Close List):存储已经检查过的节点,避免重复处理
  • 启发函数(Heuristic Function):计算h(n)的函数,常用曼哈顿距离、欧几里得距离等

基础节点类定义

首先需要定义节点类,存储节点的核心属性,代码如下:

// 定义网格节点类
public class PathNode
{
    // 节点在网格中的x坐标
    public int X { get; set; }
    // 节点在网格中的y坐标
    public int Y { get; set; }
    // 从起点到当前节点的实际代价g
    public int G { get; set; }
    // 当前节点到终点的预估代价h
    public int H { get; set; }
    // 总代价f = g + h
    public int F => G + H;
    // 父节点,用于回溯路径
    public PathNode Parent { get; set; }
    // 节点是否可通行
    public bool IsWalkable { get; set; }

    public PathNode(int x, int y, bool isWalkable = true)
    {
        X = x;
        Y = y;
        IsWalkable = isWalkable;
        G = 0;
        H = 0;
        Parent = null;
    }
}

启发函数实现

这里使用曼哈顿距离作为启发函数,适合网格只能上下左右移动的寻路场景,代码如下:

// 计算两个节点之间的曼哈顿距离作为启发值h
public static int CalculateManhattanDistance(PathNode a, PathNode b)
{
    return Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y);
}

A*算法核心实现

核心逻辑包含初始化列表、选取最小f节点、扩展相邻节点、更新代价、回溯路径几个步骤,完整实现如下:

using System;
using System.Collections.Generic;
using System.Linq;

public class AStarPathfinding
{
    // 网格地图,二维数组表示,true为可通行
    private PathNode[,] grid;
    // 网格行数
    private int rows;
    // 网格列数
    private int cols;

    public AStarPathfinding(PathNode[,] mapGrid)
    {
        grid = mapGrid;
        rows = grid.GetLength(0);
        cols = grid.GetLength(1);
    }

    // 寻路主方法,返回路径节点列表,无路径返回空列表
    public List<PathNode> FindPath(PathNode start, PathNode end)
    {
        // 开放列表,存储待检查的节点
        List<PathNode> openList = new List<PathNode>();
        // 关闭列表,存储已检查的节点
        HashSet<PathNode> closeSet = new HashSet<PathNode>();

        // 初始化起点
        start.G = 0;
        start.H = CalculateManhattanDistance(start, end);
        openList.Add(start);

        while (openList.Count > 0)
        {
            // 从开放列表中找到f值最小的节点
            PathNode current = openList.OrderBy(n => n.F).First();

            // 如果当前节点是终点,回溯路径
            if (current.X == end.X && current.Y == end.Y)
            {
                return RetracePath(start, end);
            }

            // 将当前节点从开放列表移到关闭列表
            openList.Remove(current);
            closeSet.Add(current);

            // 获取当前节点的所有相邻可通行节点
            List<PathNode> neighbors = GetNeighbors(current);

            foreach (var neighbor in neighbors)
            {
                // 如果邻居不可通行或者在关闭列表中,跳过
                if (!neighbor.IsWalkable || closeSet.Contains(neighbor))
                {
                    continue;
                }

                // 计算从起点经过当前节点到邻居的g值
                int newG = current.G + 1;

                // 如果邻居不在开放列表中,或者新的g值更小,更新邻居属性
                if (!openList.Contains(neighbor) || newG < neighbor.G)
                {
                    neighbor.G = newG;
                    neighbor.H = CalculateManhattanDistance(neighbor, end);
                    neighbor.Parent = current;

                    if (!openList.Contains(neighbor))
                    {
                        openList.Add(neighbor);
                    }
                }
            }
        }

        // 开放列表为空仍未找到终点,返回空路径
        return new List<PathNode>();
    }

    // 获取当前节点的相邻节点(上下左右四个方向)
    private List<PathNode> GetNeighbors(PathNode node)
    {
        List<PathNode> neighbors = new List<PathNode>();

        // 上
        if (node.Y > 0)
        {
            neighbors.Add(grid[node.Y - 1, node.X]);
        }
        // 下
        if (node.Y < rows - 1)
        {
            neighbors.Add(grid[node.Y + 1, node.X]);
        }
        // 左
        if (node.X > 0)
        {
            neighbors.Add(grid[node.Y, node.X - 1]);
        }
        // 右
        if (node.X < cols - 1)
        {
            neighbors.Add(grid[node.Y, node.X + 1]);
        }

        return neighbors;
    }

    // 回溯路径,从终点反向找到起点
    private List<PathNode> RetracePath(PathNode start, PathNode end)
    {
        List<PathNode> path = new List<PathNode>();
        PathNode current = end;

        while (current != start)
        {
            path.Add(current);
            current = current.Parent;
        }
        path.Add(start);
        // 反转路径,从起点到终点
        path.Reverse();

        return path;
    }
}

使用示例

下面演示如何初始化地图并调用寻路方法,代码如下:

class Program
{
    static void Main(string[] args)
    {
        // 初始化5x5的网格地图,true表示可通行
        PathNode[,] grid = new PathNode[5, 5];
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 5; x++)
            {
                // 这里可以设置部分节点不可通行,比如(2,2)位置为障碍物
                bool isWalkable = (x == 2 && y == 2) ? false : true;
                grid[y, x] = new PathNode(x, y, isWalkable);
            }
        }

        // 定义起点(0,0)和终点(4,4)
        PathNode startNode = grid[0, 0];
        PathNode endNode = grid[4, 4];

        // 创建A*寻路实例
        AStarPathfinding astar = new AStarPathfinding(grid);
        // 执行寻路
        List<PathNode> path = astar.FindPath(startNode, endNode);

        // 输出路径结果
        if (path.Count > 0)
        {
            Console.WriteLine("寻路成功,路径节点坐标:");
            foreach (var node in path)
            {
                Console.WriteLine($"({node.X}, {node.Y})");
            }
        }
        else
        {
            Console.WriteLine("未找到可达路径");
        }
    }
}

注意事项

实际使用中可以根据需求调整以下部分:

  • 如果需要支持斜向移动,修改GetNeighbors方法添加四个斜向相邻节点,同时调整g值计算,斜向移动的g值通常设为√2取整或者1.4
  • 启发函数可以根据场景替换,比如允许斜向移动时可以使用欧几里得距离
  • 开放列表的排序操作如果地图较大,建议使用优先队列(PriorityQueue)优化性能,避免每次遍历查找最小f节点
  • 网格地图可以根据实际需求替换为其他地图结构,只需要调整节点的相邻节点获取逻辑即可

C#A_Star_algorithmpathfindinggrid_map修改时间:2026-07-13 07:33:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。