最短路径查找算法C#
最近在做一个导航算法,研究无果之后,在网上终于找到相关代码,在这里感谢ioly.
using System; using System.Collections.Generic; using System.Text; namespace Test { /// <summary> /// 接口:点间连线 /// </summary> public interface ILine { /// <summary> /// 开始节点ID /// </summary> string SrcId { get; set; } /// <summary> /// 结束节点ID /// </summary> string DstId { get; set; } /// <summary> /// 连线的权重。必需大于0 /// </summary> int Weight { get; set; } } /// <summary> /// 测试类:点间连线 /// </summary> public class TestLine : ILine { private string _src_id; private string _dst_id; private int _weight; public TestLine(string src_id, string dst_id, int weight) { _src_id = src_id; _dst_id = dst_id; _weight = weight; } /// <summary> /// 出发点 /// </summary> public string SrcId { get { return _src_id; } set { _src_id = value; } } /// <summary> /// 目标点 /// </summary> public string DstId { get { return _dst_id; } set { _dst_id = value; } } /// <summary> /// 权重 /// </summary> public int Weight { get { return _weight; } set { _weight = value; } } /// <summary> /// 转换为字符串 /// </summary> public override string ToString() { return string.Format("{0} - {1}", _src_id, _dst_id); } } /// <summary> /// 实现点间最小权重路径算法 /// </summary> public class RoadFinder { /// <summary> /// 已知路线的查找表。key:src_id.dst_id, value: ILine /// </summary> private Dictionary<string, ILine> dct_lines = new Dictionary<string, ILine>(); /// <summary> /// 邻接节点 /// </summary> private Dictionary<string, List<string>> dct_relate = new Dictionary<string, List<string>>(); /// <summary> /// 查找两点间的最短路径(路径权重和最小) /// </summary> /// <param name="src_id">出发点ID</param> /// <param name="dst_id">目标点ID</param> /// <param name="lines">已知的所有连接线</param> /// <returns>最短路径的连接线</returns> public bool FindRoad(string src_id, string dst_id, IEnumerable<ILine> enu_lines, out List<ILine> lst_result) { //初始化缓存 this.dct_lines.Clear(); this.dct_relate.Clear(); foreach (ILine item in enu_lines) { this.dct_lines[string.Format("{0}.{1}", item.SrcId, item.DstId)] = item; this.dct_lines[string.Format("{1}.{0}", item.SrcId, item.DstId)] = item; _PutRelatingPoint(item.SrcId, item.DstId); _PutRelatingPoint(item.DstId, item.SrcId); } List<string> lst_visited = new List<string>(); return _Find(src_id, dst_id, lst_visited, out lst_result); } /// <summary> /// 添加关联节点 /// </summary> /// <param name="point_id">起始点ID</param> /// <param name="related_id">关联点ID</param> void _PutRelatingPoint(string point_id, string related_id) { List<string> lst; if (this.dct_relate.TryGetValue(point_id, out lst)) { lst.Add(related_id); } else { lst = new List<string>(); lst.Add(related_id); this.dct_relate[point_id] = lst; } } /// <summary> /// 递归查找点间最小权重的路径 /// </summary> /// <param name="src_id">出发点ID</param> /// <param name="dst_id">目标点ID</param> /// <param name="lst_visited">已访问的节点列表</param> /// <param name="enu_lines">返回连线</param> /// <returns>如果找到,返回true</returns> bool _Find(string src_id, string dst_id, List<string> lst_visited, out List<ILine> lst_result) { lst_result = null; lst_visited.Add(src_id); //记录最小权重 int weight = -1; ILine line; if (_HasDirectLine(src_id, dst_id, out line)) { //存在直接连线 lst_result = new List<ILine>(); lst_result.Add(line); weight = line.Weight; } //递归遍历邻接点是否存在最短路径 { int count = lst_visited.Count; bool found_relate = false; List<string> lst_relate; if (this.dct_relate.TryGetValue(src_id, out lst_relate)) { foreach (string point_id in lst_relate) { if (lst_visited.Contains(point_id)) continue; List<ILine> lst_temp; if (_Find(point_id, dst_id, lst_visited, out lst_temp)) { lst_temp.Insert(0, this.dct_lines[string.Format("{0}.{1}", src_id, point_id)]); int w = _GetWeight(lst_temp); if (weight == -1 || w < weight) { weight = w; lst_result = lst_temp; found_relate = true; } } } } lst_visited.RemoveRange(count, lst_visited.Count - count); if (found_relate) return true; } return lst_result != null; } /// <summary> /// 判断两点间是否存在直接连线 /// </summary> /// <param name="src_id">出发点ID</param> /// <param name="dst_id">目标点ID</param> /// <param name="line">连接线</param> /// <returns>如果存在直接连线,返回true</returns> bool _HasDirectLine(string src_id, string dst_id, out ILine line) { return this.dct_lines.TryGetValue(string.Format("{0}.{1}", src_id, dst_id), out line); } /// <summary> /// 计算路径的权重和 /// </summary> /// <param name="enu_lines">连接线</param> /// <returns>权重和</returns> int _GetWeight(IEnumerable<ILine> enu_lines) { int total = 0; foreach (ILine item in enu_lines) total += item.Weight; return total; } /// <summary> /// 测试方法 /// </summary> public static void Test() { List<ILine> lst_lines = new List<ILine>(); //A - B lst_lines.Add(new TestLine("A", "B", 1)); //B - C lst_lines.Add(new TestLine("B", "C", 1)); //C - D lst_lines.Add(new TestLine("C", "D", 1)); //B - D //lst_lines.Add(new TestLine("B", "D", 1)); List<ILine> lst_result; RoadFinder finder = new RoadFinder(); if (finder.FindRoad("A", "D", lst_lines, out lst_result)) { foreach (ILine line in lst_result) Console.WriteLine(line); } } } }
世事洞明皆学问,勿以善小而不为!