C#最短路径算法demo

来源:互联网 发布:淘宝待评价怎么消除 编辑:程序博客网 时间:2024/06/07 02:17

我们的物流系统正好需要个路由功能,

也就是两个服务站之间推荐出最短的配送路径,

于是用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;                }            }            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 && notRemovePathList.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    }}



0 0
原创粉丝点击