如下图所示,一个节点图,每一个字母代表一个节点,每两个节点之间的数字表示距离,两节点之间的箭头表示指向;
请用代码计算出 节点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 之间的最短路径,如下图: