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
}
}


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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • mysql分页查询limit用法(怎么对文档进行分页)

    一、分页需求:客户端通过传递start(页码),pageSize(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limitm,n,但是该函数的用法和我们的需求不一样,所以就需要我们根据实际情况去改写适合我们自己的分页语句,具体的分析如下:比如:查询第1条到第10条的数据的sql是:select*fromtablelimit0,…

  • Laravel 从入门到精通系列教程

    Laravel 从入门到精通系列教程

  • CentOS7离线安装gcc

    CentOS7离线安装gcc安装Redis时,需要使用gcc。如果系统是联网的,那么直接使用如下命令联网安装。yum-yinstallgcc但是如果系统不可联网,那么就需要一种离线安装的方式了。步骤如下:1.从CentOS7的系统安装镜像中取出需要的rpm包(也可以通过别的方式获取):解压镜像文件,进入"Packages"目录,里面很多rpm包,取出如下几个:mpfr-3.1.1-4.el7….

  • SVN服务器搭建和使用[通俗易懂]

    SVN服务器搭建和使用[通俗易懂]SVN服务器搭建和使用

  • CV2模块使用(详细教程)

    CV2模块使用(详细教程)

  • 2021年最好用&完全免费的图片压缩网站、软件推荐(包括GIF)

    2021年最好用&完全免费的图片压缩网站、软件推荐(包括GIF)最近我有遇到一个很奇怪的问题因为我不是转用AppleMusic本地化听歌了????所以很多歌的歌曲信息都是我自己补充的,当然也包括封面但我在用iTunes把歌传到iPhone上来听的时候,有首歌的封面怎么都同步不过来我来回同步了几遍,还重新连接了几次,甚至换回了有线来同步,这个封面始终都还是同步不上…我就一直奇了怪了直到我想重新编辑一下封面,重新添加,我才发现…好家伙,一张封面竟然有18M!?比我MP3本身都要大了,难怪我添加不上呢完全被它小小的外表给欺骗了我后来把图片

发表回复

您的电子邮箱地址不会被公开。

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