public class Route<T> { public string FullRoute { get; } public Route(Stack<T> stack) { FullRoute = string.Join(",", stack); } }
public class MyGraph<TNode, TWeight> where TWeight : IComparable<TWeight> { //节点表 private readonly Dictionary<TNode, Dictionary<TNode, TWeight>> _nodes; //权重表,存储节点最新的权重值 private readonly Dictionary<TNode, TWeight> _weights; //父节点表 private readonly Dictionary<TNode, TNode> _parents; //权重计算委托 private readonly Func<TWeight, TWeight, TWeight> _weightAddDelegate; //已搜索元素的集合 private HashSet<TNode> _searchedNodes; public MyGraph(Dictionary<TNode, Dictionary<TNode, TWeight>> nodes, Dictionary<TNode, TWeight> weights, Dictionary<TNode, TNode> parents, Func<TWeight, TWeight, TWeight> weightAddDelegate) { _nodes = nodes; _weights = weights; _parents = parents; _weightAddDelegate = weightAddDelegate; } /// <summary> /// 找最小权重 /// </summary> /// <param name="start">起点</param> /// <param name="end">终点</param> /// <param name="route">路线</param> /// <returns></returns> public TWeight FindMinWeight(TNode start, TNode end, out Route<TNode> route) { if (_nodes.ContainsKey(start) == false) { throw new Exception("not find the start node:" + start); } if (_nodes.ContainsKey(end) == false) { throw new Exception("not find the end node:" + end); } _searchedNodes = new HashSet<TNode>(); var minWeightNode = FindLowestWeightAndNotSearchedNode(); while (EqualityComparer<TNode>.Default.Equals(minWeightNode, default) == false) { //遍历当前节点(minWeightNode)指向的所有节点(item). foreach (var item in _nodes[minWeightNode]) { //计算这些节点的权重 //权重 = 这些节点对于当前节点的权重 + 当前节点最新的权重 var newWeight = _weightAddDelegate(item.Value, _weights[minWeightNode]); if (newWeight.CompareTo(_weights[item.Key]) > 0) { continue; } //更新权重表和父节点表. _weights[item.Key] = newWeight; _parents[item.Key] = minWeightNode; } //当前节点搜索完毕后,添加到已搜索集合. _searchedNodes.Add(minWeightNode); minWeightNode = FindLowestWeightAndNotSearchedNode(); } route = GetRoute(end); return _weights[end]; } /// <summary> /// 找出权重最小,且还未搜索过的节点. /// </summary> /// <returns></returns> public TNode FindLowestWeightAndNotSearchedNode() { foreach (var keyValuePair in _weights.OrderBy(o => o.Value)) { if (_searchedNodes.Contains(keyValuePair.Key) == false) { return keyValuePair.Key; } } return default; } /// <summary> /// 获取路线 /// </summary> /// <param name="end"></param> /// <returns></returns> private Route<TNode> GetRoute(TNode end) { var stack = new Stack<TNode>(); stack.Push(end); TNode node = end; while (_parents.TryGetValue(node, out var parent) == true) { stack.Push(parent); node = parent; } return new Route<TNode>(stack); } }
Test:
Dictionary<string, Dictionary<string, int>> nodeDic = new Dictionary<string, Dictionary<string, int>>(); nodeDic.Add("start", new Dictionary<string, int> { { "a", 5 }, { "c", 2 } }); nodeDic.Add("a", new Dictionary<string, int> { { "b", 4 }, { "d", 4 } }); nodeDic.Add("b", new Dictionary<string, int> { { "d", 1 }, { "end", 3 } }); nodeDic.Add("c", new Dictionary<string, int> { { "a", 1 }, { "d", 3 }, { "b", 10 } }); nodeDic.Add("d", new Dictionary<string, int> { { "end", 8 } }); nodeDic.Add("end", new Dictionary<string, int>()); Dictionary<string, int> costDic = new Dictionary<string, int> { {"a",5 }, {"c",2 }, {"b",int.MaxValue }, {"d",int.MaxValue }, {"end",int.MaxValue } }; Dictionary<string, string> parentsDic = new Dictionary<string, string> { {"a","start" }, {"c","start" }, {"b",null }, {"d",null }, {"end",null }, }; Func<int, int, int> @delegate = (x, y) => x + y; MyGraph<string, int> g = new MyGraph<string, int>(nodeDic, costDic, parentsDic, @delegate); var result = g.FindMinWeight("start", "end", out var route); Console.WriteLine(result); Console.WriteLine(route.FullRoute);