C#最短路径算法demo
2016-06-19 01:38
519 查看
我们的物流系统正好需要个路由功能,
也就是两个服务站之间推荐出最短的配送路径,
于是用C#写了个最短路径算法,并封装成DLL了
整个demo见文件:点击下载源码
例子截图:
代码:
也就是两个服务站之间推荐出最短的配送路径,
于是用C#写了个最短路径算法,并封装成DLL了
整个demo见文件:点击下载源码
例子截图:
代码:
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BLL { public class ShortestPathEngine { private static ShortestPathEngine _instance; /// <summary> /// 获取最短路径解析引擎实例 /// </summary> /// <returns></returns> public static ShortestPathEngine GetInstance() { if (_instance == null) { _instance = new ShortestPathEngine(); } return _instance; } #region (共有方法) /// <summary> /// 获取开始节点到其它节点的最短路径集合 /// </summary> /// <param name="fromPoint">开始节点</param> /// <param name="toPoint">目的节点</param> /// <param name="dt">地址表</param> /// <param name="msg">提示消息</param> /// <returns>最短路径集合</returns> public List<ShortPath> GetShortestPath(string fromPoint, string toPoint, DataTable dt, out string msg) { msg = string.Empty; try { List<string> pointNameU = new List<string>();//剩余顶点 List<string> pointNameS = new List<string>();//已求出最短路径的顶点的集合 List<ShortPath> shortPathList = new List<ShortPath>();//最短路径对象集合 List<LastShortPath> lastShortPathList = new List<LastShortPath>();//上一个最短路径对象集合 List<NotRemovePath> notRemovePathList = new List<NotRemovePath>();//未被移除的路径对象集合 pointNameU = GetAllPointName(dt); bool isCheck = CheckPoint(pointNameU, fromPoint, toPoint, out msg); if (!isCheck) { return null; } //---start 计算第一个最短路径 string nextPoint = fromPoint;//下个最短节点 string startPoint = fromPoint;//开始节点 int distance = GetDistance(fromPoint, nextPoint, dt); string path = string.Format("{0},{1}", fromPoint, nextPoint); pointNameS.Add(fromPoint);//添加,已为最短路径的节点 pointNameU.Remove(fromPoint);//从剩余节点移除 new ShortPathList(shortPathList).AddShortPath(startPoint, nextPoint, path, distance);//添加到最短路径集合 //---end List<string> centerPointList = new List<string>();//中间节点 centerPointList.Add(nextPoint); ResolveCenterPointShortPaths(centerPointList, dt, pointNameU, pointNameS, notRemovePathList, shortPathList, lastShortPathList, startPoint); if (shortPathList == null || shortPathList.Count == 0) { msg = string.Format("不存在{0}节点到其它节点的最短路径", fromPoint); return null; } else { return shortPathList; } 4000 } catch { msg = "最短路径计算失败,请重试"; return null; } } /// <summary> /// 获取开始节点到目的节点的最短路径集合 /// </summary> /// <param name="shortPathList">开始节点到其它节点的最短路径集合</param> /// <param name="fromPoint">开始节点</param> /// <param name="toPoint">目的节点</param> /// <param name="msg">提示消息</param> /// <returns>最短路径集合</returns> public List<ShortPath> GetShortPathListResult(List<ShortPath> shortPathList, string fromPoint, string toPoint, out string msg) { msg = string.Empty; List<ShortPath> shortPathListResult = shortPathList.FindAll(p => p.fromPoint == fromPoint && p.toPoint == toPoint); return shortPathListResult; } public DataTable GetResultPathDt(List<ShortPath> shortPathList) { DataTable dt = new DataTable(); dt.Columns.Add("开始节点", typeof(string));//开始节点 dt.Columns.Add("目的节点", typeof(string));//目的节点 dt.Columns.Add("里程", typeof(int));//距离 dt.Columns.Add("最短路径", typeof(string));//路径 foreach (ShortPath shortPath in shortPathList) { DataRow dr = dt.NewRow(); dr["开始节点"] = shortPath.fromPoint; dr["目的节点"] = shortPath.toPoint; dr["里程"] = shortPath.distanceSum; dr["最短路径"] = shortPath.path; dt.Rows.Add(dr); } return dt; } #endregion #region (私有方法) /// <summary> /// 批量解析中间节点最近的路径 /// </summary> /// <param name="centerPointList">中间节点集合</param> /// <param name="dt">地址表</param> /// <param name="pointNameU">剩余顶点</param> /// <param name="pointNameS">已求出最短路径节点</param> /// <param name="shortPathList">最短路径集合</param> /// <param name="pathTemp">临时路径集合</param> /// <returns></returns> private void ResolveCenterPointShortPaths(List<string> centerPointList, DataTable dt, List<string> pointNameU, List<string> pointNameS, List<NotRemovePath> notRemovePathList, List<ShortPath> shortPathList, List<LastShortPath> lastShortPathList, string startPoint) { List<string> nextCenterPointListTemp = new List<string>();//下一个中间节点集合 centerPointList = centerPointList.Distinct().ToList(); foreach (string centerPoint in centerPointList) { ResolveCenterPointShortPathFast(centerPoint, dt, pointNameU, pointNameS, nextCenterPointListTemp, notRemovePathList, shortPathList, lastShortPathList, startPoint); } //将notRemovePathList最短路径集合添加到最短路径) AddShortestFromNotMoveList(pointNameU, pointNameS, nextCenterPointListTemp, notRemovePathList, shortPathList, lastShortPathList, startPoint); if (pointNameU.Count > 0 && nextCenterPointListTemp.Count > 0)//如果,还有剩余节点&有下个中间节点,则继续 { ResolveCenterPointShortPaths(nextCenterPointListTemp, dt, pointNameU, pointNameS, notRemovePathList, shortPathList, lastShortPathList, startPoint); } } /// <summary> /// 解析单个中间节点最近的路径(更快更简单的算法) /// </summary> /// <param name="centerPoint">中间节点</param> /// <param name="dt">地址表</param> /// <param name="pointNameU">剩余顶点</param> /// <param name="pointNameS">已求出最短路径节点</param> /// <param name="shortPathList">最短路径集合</param> /// <param name="pathTemp">临时路径集合</param> /// <returns></returns> private void ResolveCenterPointShortPathFast(string centerPoint, DataTable dt, List<string> pointNameU, List<string> pointNameS, List<string> nextCenterPointListTemp, List<NotRemovePath> notRemovePathList, List<ShortPath> shortPathList, List<LastShortPath> lastShortPathList, string startPoint) { string strU = string.Join("','", pointNameU); dt.DefaultView.RowFilter = string.Format("fromPoint='{0}' and toPoint in('{1}')", centerPoint, strU); dt.DefaultView.Sort = "distance asc"; DataTable dtFromPointPathALL = dt.DefaultView.ToTable();//中间节点的所有直接路径 #region (添加到未移除集合) if (dtFromPointPathALL.Rows.Count > 0) { LastShortPath lastShortPath=null; foreach (DataRow dr in dtFromPointPathALL.Rows) { string nextPoint = dr["toPoint"].ToString(); string path = string.Format("{0},{1}", centerPoint, nextPoint); int distanceSum = GetDistance(centerPoint, nextPoint, dt); if (lastShortPathList.Count == 0)//无上次最短节点 { notRemovePathList.Add(new NotRemovePath { path = path, distanceSum = distanceSum, toPoint = nextPoint }); } else { lastShortPath = lastShortPathList.Find(p => p.lastPoint == centerPoint); path = string.Format("{0},{1}", lastShortPath.path, nextPoint); distanceSum = lastShortPath.distanceSum + distanceSum; notRemovePathList.Add(new NotRemovePath { path = path, distanceSum = distanceSum, toPoint = nextPoint }); } } if (lastShortPath != null) { lastShortPathList.Remove(lastShortPath); } } #endregion } /// <summary> /// 获取两节点距离 /// </summary> /// <param name="fromPoint">开始节点</param> /// <param name="toPoint">目的节点</param> /// <param name="dt">地址表</param> /// <returns>距离</returns> private int GetDistance(string fromPoint, string toPoint, DataTable dt) { dt.DefaultView.RowFilter = string.Format("fromPoint='{0}' and toPoint='{1}' ", fromPoint, toPoint); DataTable dtDistance = dt.DefaultView.ToTable(); if (dtDistance != null && dtDistance.Rows.Count > 0) { return int.Parse(dtDistance.Rows[0]["distance"].ToString()); } else { return 0; } } /// <summary> /// 获取所有去重后顶点 /// </summary> /// <param name="dt">顶点路径表</param> /// <returns></returns> private List<string> GetAllPointName(DataTable dt) { List<string> pointNameU = new List<string>(); DataTable dtFromPoint = dt.DefaultView.ToTable(true, new string[] { "fromPoint" }); dtFromPoint.Columns["fromPoint"].ColumnName = "pointName"; DataTable dtToPoint = dt.DefaultView.ToTable(true, new string[] { "toPoint" }); dtToPoint.Columns["toPoint"].ColumnName = "pointName"; dtFromPoint.Merge(dtToPoint); DataTable dtPointName = dtFromPoint.DefaultView.ToTable(true, new string[] { "pointName" }); if (dtPointName != null && dtPointName.Rows.Count > 0) { foreach (DataRow drPoint in dtPointName.Rows) { pointNameU.Add(drPoint["pointName"].ToString()); } } return pointNameU; } /// <summary> /// 将notRemovePathList最短路径集合添加到最短路径 /// </summary> /// <param name="pointNameU"></param> /// <param name="pointNameS"></param> /// <param name="nextCenterPointListTemp"></param> /// <param name="notRemovePathList"></param> /// <param name="shortPathList"></param> /// <param name="lastShortPathList"></param> /// <param name="startPoint"></param> private static void AddShortestFromNotMoveList(List<string> pointNameU, List<string> pointNameS, List<string> nextCenterPointListTemp, List<NotRemovePath> notRemovePathList, List<ShortPath> shortPathList, List<LastShortPath> lastShortPathList, string startPoint) { if (notRemovePathList.Count == 0) { return; } else { NotRemovePath notRemovePathTemp = notRemovePathList.OrderBy(p => p.distanceSum).First(); List<NotRemovePath> notRemovePathListTemp = notRemovePathList.FindAll(p => p.distanceSum == notRemovePathTemp.distanceSum); foreach (NotRemovePath notRemovePath in notRemovePathListTemp) { string nextPoint = notRemovePath.toPoint; string path = notRemovePath.path; int distanceSum = notRemovePath.distanceSum; pointNameS.Add(nextPoint); pointNameU.Remove(nextPoint); new ShortPathList(shortPathList).AddShortPath(startPoint, nextPoint, path, distanceSum); lastShortPathList.Add(new LastShortPath() { lastPoint = nextPoint, distanceSum = distanceSum, path = path }); nextCenterPointListTemp.Add(nextPoint);//添加到下一个中间节点集合 notRemovePathList.Remove(notRemovePath); List<NotRemovePath> notRemovePaths = notRemovePathList.FindAll(p => p.toPoint == nextPoint); foreach (NotRemovePath item in notRemovePaths) { if (item != null) { notRemovePathList.Remove(item); } } // RecordNotRemovePath(centerPoint, dt, pointNameU, notRemovePathList, strU, distance); } } } /// <summary> /// 校验节点是否在地址表里 /// </summary> /// <param name="pointNameU">所有顶点</param> /// <param name="fromPoint">开始节点</param> /// <param name="toPoint">目的节点</param> /// <param name="msg">提示消息</param> /// <returns>成功与否</returns> private bool CheckPoint(List<string> pointNameU, string fromPoint, string toPoint, out string msg) { msg = "节点在地址表内"; if (!pointNameU.Contains(fromPoint)) { msg = "开始节点不在地址表内"; return false; } if (!pointNameU.Contains(toPoint)) { msg = "结束节点不在地址表内"; return false; } return true; } #endregion } }
相关文章推荐
- C#访问修饰符
- C# TextBox
- LeetCode #20 Valid Parentheses C# Solution
- C#设计模式—装饰模式
- C# IO有关操作
- c#获取console类进程程序的显示数值
- c#从大图截取一部分图片
- C# 中List类 小叙
- C#常用的加密解密方法
- C#导出EXCEL代码1
- C#导出EXCEL文件代码1
- C#语言基础
- C# Iterator迭代器的实现方式
- c#加密解密源码,md5、des、rsa
- C#设计模式—组合模式
- 4 我们的第一个c#程序
- C#中数组与ArrayList的简单使用
- C#中Dynamic关键字
- 【C#】第3章学习要点(一)--整体把握
- ado.net 实体框架快速入门学习