节点图找出最短路径 C# 实现

如下图所示,一个节点图,每一个字母代表一个节点,每两个节点之间的数字表示距离,两节点之间的箭头表示指向
请用代码计算出 节点c节点f 之间的最短路径。

在这里插入图片描述

示例代码已放在 GitHub 上,如下链接:
示例代码

核心代码如下

    /// <summary>
    /// 节点
    /// </summary>
    public class Node
    {
        public Node(string nodeName)
        {
            this.NodeName = nodeName;
        }

        public Node(string nodeName, Dictionary<string, double> everyPath)
        {
            this.NodeName = nodeName;
            this.EveryPath = everyPath;
        }


        /// <summary>
        /// 节点名
        /// </summary>
        public string NodeName { get; set; }

        /// <summary>
        /// 当前节点的每一条路径
        /// <para>字典集合中的 key 是当前节点所指向的下一个节点名</para>
        /// <para>字典集合中的 value 是两个节点之间的距离</para>
        /// </summary>
        public Dictionary<string, double> EveryPath { get; set; } = new Dictionary<string, double>();
    }
    /// <summary>
    /// 节点路径
    /// </summary>
    public class NodePath
    {
        public NodePath(Dictionary<string, Node> nodes)
        {
            this.Nodes = nodes;
        }


        private readonly StringBuilder _sbPath = new StringBuilder();

        private readonly List<string> _pathList = new List<string>();

        private readonly Dictionary<string, double> _pathLengthDic = new Dictionary<string, double>();

        /// <summary>
        /// 用来存放所有的节点
        /// </summary>
        public Dictionary<string, Node> Nodes { get; set; }


        /// <summary>
        /// 找出 路
        /// </summary>
        /// <param name="startNode"></param>
        /// <param name="endNode"></param>
        private void FindoutPath(string startNode, string endNode)
        {
            if (!Nodes.ContainsKey(startNode))
            {
                return;
            }

            if (startNode == endNode)
            {
                _sbPath.Append($"-{endNode}");
                _sbPath.AppendLine();
                return;
            }

            var nodePath = Nodes[startNode].EveryPath;
            if (nodePath == null || nodePath.Count < 1)
            {
                _sbPath.AppendLine();
                return;
            }
            else
            {
                foreach (var item in nodePath)
                {
                    _sbPath.Append($"-{startNode}");
                    FindoutPath(item.Key, endNode);
                }
            }
        }

        /// <summary>
        /// 获取两节点之间的所有路径
        /// </summary>
        /// <param name="startNode"></param>
        /// <param name="endNode"></param>
        /// <returns></returns>
        private bool GetAllPath(string startNode, string endNode)
        {
            _sbPath.Clear();
            _pathList.Clear();
            _pathLengthDic.Clear();

            FindoutPath(startNode, endNode);

            var pathArr = _sbPath.ToString().Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
            foreach (var item in pathArr)
            {
                if (!item.Contains($"-{startNode}"))
                {
                    _pathList.Add($"-{startNode}{item}");
                }
                else
                {
                    _pathList.Add(item);
                }
            }

            for (int i = 0; i < _pathList.Count; i++)
            {
                string path = _pathList[i].Remove(0, 1);
                if (path.Contains($"{startNode}-") && path.Contains($"-{endNode}"))
                {
                    _pathList[i] = path;
                }
                else
                {
                    _pathList[i] = null;
                }
            }

            _pathList.RemoveAll(x =>
            {
                return string.IsNullOrWhiteSpace(x);
            });

            return _pathList.Count > 0;
        }


        /// <summary>
        /// 计算最短路径
        /// </summary>
        /// <param name="startNode"></param>
        /// <param name="endNode"></param>
        /// <returns></returns>
        public (string Path, double Length, List<KeyValuePair<string, double>> AllPath) ComputeShortestPath(string startNode, string endNode)
        {
            if (!GetAllPath(startNode, endNode))
            {
                return (string.Empty, -1, null);
            }

            foreach (var item in _pathList)
            {
                var nodeIds = item.Split("-", StringSplitOptions.RemoveEmptyEntries);
                string tempNodeId = startNode;
                double length = 0.0;
                foreach (var nodeId in nodeIds)
                {
                    if (nodeId == startNode)
                    {
                        continue;
                    }

                    length += Nodes[tempNodeId].EveryPath[nodeId];

                    tempNodeId = nodeId;
                }
                _pathLengthDic.Add(item, length);
            }

            var temp = _pathLengthDic.OrderBy(x => x.Value).ToList();

            return (temp[0].Key, temp[0].Value, temp);
        }
    }
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Console.WriteLine();
            Console.WriteLine();

            #region 初始化一些节点数据
            Node a = new Node("a");
            a.EveryPath.Add("b", 2);
            a.EveryPath.Add("c", 6);

            Node b = new Node("b");
            b.EveryPath.Add("e", 5);
            b.EveryPath.Add("d", 5);

            Node c = new Node("c");
            c.EveryPath.Add("e", 3);
            c.EveryPath.Add("f", 7);
            c.EveryPath.Add("d", 8);

            Node d = new Node("d");
            d.EveryPath.Add("f", 10);

            Node e = new Node("e");
            e.EveryPath.Add("f", 7);

            Node f = new Node("f");
            #endregion

            Dictionary<string, Node> nodes = new Dictionary<string, Node>()
            {
                { nameof(a), a },
                { nameof(b), b },
                { nameof(c), c },
                { nameof(d), d },
                { nameof(e), e },
                { nameof(f), f }
            };

            NodePath nodesPath = new NodePath(nodes);

            string startNode = "c";
            string endNode = "f";
            var shortestPath = nodesPath.ComputeShortestPath(startNode, endNode);

            Console.WriteLine($"节点 {startNode} --> 节点 {endNode}");
            Console.WriteLine();
            Console.WriteLine("路长\t路径");
            Console.WriteLine("---------------------------------------------");
            Console.WriteLine();

            if (shortestPath.AllPath == null)
            {
                Console.WriteLine($"此路不通");
            }
            else
            {
                Console.WriteLine("最短路径:");
                Console.WriteLine($"{shortestPath.Length}\t{shortestPath.Path}");
                Console.WriteLine();
                Console.WriteLine("所有路径:");
                foreach (var item in shortestPath.AllPath)
                {
                    Console.WriteLine($"{item.Value}\t{item.Key}");
                }
            }

            Console.WriteLine();
            Console.WriteLine("---------------------------------------------");

            Console.ReadKey();
        }
    }

示例运行效果,如下图:
在这里插入图片描述

如果是 节点a节点f 之间的最短路径,如下图:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值