C#最短路径算法demo

C#最短路径算法demoC#最短路径算法源码和demo

大家好,又见面了,我是你们的朋友全栈君。

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

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

于是用C#写了个最短路径算法,并封装成DLL了

整个demo见文件:点击下载源码

例子截图:

C#最短路径算法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 && 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

    }
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/139487.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • debian系统里面 dpkg命令怎么使用

    debian系统里面 dpkg命令怎么使用dpkg是Debian的中级软件包管理器,类似RPM.dpkg是Debian软件包管理系统的中流砥柱,负责安全卸载软件包,配置,以及维护已安装的软件包.也是Debian系统中众多软件包管理工具的后端.有关dpkg的更多介绍参阅:http://www.dpkg.org系统中所有packages的信息都在/var/lib/dpkg/目录下,其中子目录”/var/lib/dpkg/info”用于…

    2022年5月21日
    45
  • Jmeter的正则表达式提取参数「建议收藏」

    Jmeter的正则表达式提取参数「建议收藏」1:Jmeter正则表达式提取器提取制定的值1.1:添加http请求(80端口不用写端口号)1.2:添加正则表达式提取器.表示匹配任意字符+表示匹配一个或者多个?表示匹配到结束为止PS:下面的正则表达式还可以写成province:'([^’]+)’,       表示:[^’]匹配到不是单引号’;+表示它内的多个字符1.3:添加Debugsampler(用Debug取样器可以方便tes…

    2025年10月21日
    3
  • B样条曲线的一些基本性质[通俗易懂]

    B样条曲线的一些基本性质[通俗易懂]1.B样条曲线的节点(knotpoint)指的是将区间划分为一段一段的分段点。节点向量(knotvector)则是由多个节点组成的向量。2.B样条曲线的次数(degree)也就是基函数的次数,而阶数(oder)则是次数加1。3.若B样条曲线由n+1个控制点(从P0到Pn),有m+1个节点(从u0到um),阶数为k+1(次数为k),则必须满足m=n+k+1。4.B样条曲线的每个控制点对应一个基函数,所有控制点与对应的基函数的乘积求和可得到B样条曲线的函数表达式。5.B样条曲线具有局部支撑性。第i+

    2022年6月18日
    75
  • commons-lang里面StringUtils方法说明以及案例

    commons-lang里面StringUtils方法说明以及案例下面总结了StringUtil里面的常用的方法:1.publicstaticbooleanisBlank(Stringstr)在校验一个String类型的变量是否为空时,通常存在3中情况是否为null 是否为"" 是否为空字符串(引号中间有空格)如:""。 制表符、换行符、换页符和回车 StringUtils的…

    2022年6月5日
    28
  • ERROR 1396 (HY000): Operation ALTER USER failed for ‘root’@’localhost’「建议收藏」

    ERROR 1396 (HY000): Operation ALTER USER failed for ‘root’@’localhost’「建议收藏」注:原因为MySql8.0.11换了新的身份验证插件(caching_sha2_password),原来的身份验证插件为(mysql_native_password)。而客户端工具NavicatPremium12中找不到新的身份验证插件(caching_sha2_password),对此,我们将mysql用户使用的登录密码加密规则还原成mysql_native_passwor…

    2022年8月12日
    16
  • ubuntu安装gcc和g++

    ubuntu安装gcc和g++依赖包含gcc和g++,只需一行命令即可sudoapt-getinstallbuild-essential查看版本g++–versiongcc–version

    2022年7月24日
    10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号