当前位置: 首页 > news >正文

C#使用MindFusion.Diagramming框架绘制流程图(3):加权图的最短路径算法

上一篇流程图示例

C#使用MindFusion.Diagramming框架绘制流程图(2):流程图示例-CSDN博客

这里我们以之前的最短路径算法为例

最短路径算法-CSDN博客

使用MindFusion.Diagramming画出流程图,并按照当前示例图实现最短路径算法

[迪杰斯特拉最短路径算法]

我们使用MindFusion.Diagramming.DiagramItem的属性Weight权重来进行处理

我们设定MindFusion.Diagramming.DiagramLink连接是双向的权重,连接的文本就显示为权重Weight

MindFusion.Diagramming.DiagramNode节点之间的最短路径

如下图:

新建窗体FormDijkstraDiagram,

窗体FormDijkstraDiagram设计器程序如下:

文件:FormDijkstraDiagram.designer.cs


namespace FlowDiagramDemo
{partial class FormDijkstraDiagram{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.diagramView1 = new MindFusion.Diagramming.WinForms.DiagramView();this.diagram1 = new MindFusion.Diagramming.Diagram();this.btnGetMinRouter = new System.Windows.Forms.Button();this.SuspendLayout();// // diagramView1// this.diagramView1.Diagram = this.diagram1;this.diagramView1.Dock = System.Windows.Forms.DockStyle.Fill;this.diagramView1.LicenseKey = null;this.diagramView1.Location = new System.Drawing.Point(0, 0);this.diagramView1.Name = "diagramView1";this.diagramView1.Size = new System.Drawing.Size(989, 679);this.diagramView1.TabIndex = 3;this.diagramView1.Text = "diagramView1";// // diagram1// this.diagram1.TouchHitDistance = null;// // btnGetMinRouter// this.btnGetMinRouter.Location = new System.Drawing.Point(14, 2);this.btnGetMinRouter.Name = "btnGetMinRouter";this.btnGetMinRouter.Size = new System.Drawing.Size(223, 37);this.btnGetMinRouter.TabIndex = 4;this.btnGetMinRouter.Text = "打印节点A到达其他节点的最短路径";this.btnGetMinRouter.UseVisualStyleBackColor = true;this.btnGetMinRouter.Click += new System.EventHandler(this.btnGetMinRouter_Click);// // FormDijkstraDiagram// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(989, 679);this.Controls.Add(this.btnGetMinRouter);this.Controls.Add(this.diagramView1);this.Name = "FormDijkstraDiagram";this.Text = "加权图(Graph)的迪杰斯特拉最短路径算法-斯内科";this.Load += new System.EventHandler(this.FormDijkstraDiagram_Load);this.ResumeLayout(false);}#endregionprivate MindFusion.Diagramming.WinForms.DiagramView diagramView1;private MindFusion.Diagramming.Diagram diagram1;private System.Windows.Forms.Button btnGetMinRouter;}
}

窗体FormDijkstraDiagram相关程序如下:

文件:FormDijkstraDiagram.cs

using MindFusion.Diagramming;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace FlowDiagramDemo
{public partial class FormDijkstraDiagram : Form{/// <summary>/// 顶点个数/// </summary>public const int VertexCount = 6;/// <summary>/// 无法直接到达的距离,无限远的距离/// </summary>public const float Infinity = 99999;/// <summary>/// 图的顶点集合,数组的每一个元素代表一个顶点【元组的第一项代表顶点名称,第二项代表是否已被访问】/// </summary>public Tuple<string, bool>[] VertexTuples = new Tuple<string, bool>[VertexCount];/// <summary>/// 表示两点之间的距离。如:/// MatrixDistance[0,1]=88 表示 【索引为0的顶点】 到 【索引为1的顶点】 之间的距离是88/// </summary>public float[,] MatrixDistance = new float[VertexCount, VertexCount];/// <summary>/// 起点到终点的最短距离/// 元组的第一项代表起点名称,第二项代表终点名称,第三项代表最短距离值,第四项代表当前最短距离的上一个顶点索引/// 本文起点名称固定设置为A,获取A到其他任何一个顶点之间的最短距离,以及运行轨迹路线/// </summary>public Tuple<string, string, float, int>[] MinDistanceTuples = new Tuple<string, string, float, int>[VertexCount];int sequence = 0;public FormDijkstraDiagram(){InitializeComponent();diagram1.AllowSelfLoops = false;//不允许自旋链接diagram1.ShowGrid = true;//显示网格diagram1.AllowUnconnectedLinks = false;//不允许用户绘制未连接到任何节点的链接diagram1.NodeCreating += Diagram1_NodeCreating;//不允许创建节点diagram1.LinkCreating += Diagram1_LinkCreating;//不允许创建连接diagram1.NodeDeleting += Diagram1_NodeDeleting;//不允许删除节点diagram1.LinkDeleting += Diagram1_LinkDeleting;//不允许删除连接}private void Diagram1_LinkDeleting(object sender, LinkValidationEventArgs e){e.Cancel = true;}private void Diagram1_NodeDeleting(object sender, NodeValidationEventArgs e){e.Cancel = true;}private void Diagram1_LinkCreating(object sender, LinkValidationEventArgs e){e.Cancel = true;}private void Diagram1_NodeCreating(object sender, NodeValidationEventArgs e){e.Cancel = true;}/// <summary>/// 初始化所有节点/// </summary>private void InitNode(){sequence = 0;//复位序列号char label = 'A';for (int i = 0; i < VertexTuples.Length; i++){VertexTuples[i] = Tuple.Create(((char)(label + i)).ToString(), false);ShapeNode diagramNode = new ShapeNode(diagram1);diagramNode.AllowIncomingLinks = true;diagramNode.AllowOutgoingLinks = true;diagramNode.Text = VertexTuples[i].Item1;diagramNode.ToolTip = VertexTuples[i].Item1;diagramNode.Font = new Font("宋体", 14);sequence++;diagramNode.Id = sequence;diagramNode.Tag = i;float x = 100;//i==0时,起点A坐标float y = 10;//i==0时,起点A坐标if (i == 1){x = 40;y = 50;}else if (i == 2){x = 90;y = 70;}else if (i == 3){x = 170;y = 60;}else if (i == 4){x = 70;y = 130;}else if (i == 5){x = 150;y = 155;}diagramNode.Bounds = new RectangleF(x, y, 15, 15);diagramNode.Shape = Shapes.Ellipse;//形状:圆diagram1.Nodes.Add(diagramNode);                }}/// <summary>/// 添加一条无向边【认为距离是无向的 即A→B,同时B→A】/// 对图来说,就是增加两条连线←→【正向连线 与 反向连线】/// </summary>/// <param name="startIndex">起始索引</param>/// <param name="endIndex">到达索引</param>/// <param name="distance">两点之间的距离</param>private void AddLink(int startIndex, int endIndex, float distance){MatrixDistance[startIndex, endIndex] = distance;//如果距离是有方向的,则去掉下面一行代码MatrixDistance[endIndex, startIndex] = distance;DiagramLink diagramLink = new DiagramLink(diagram1, diagram1.Nodes[startIndex], diagram1.Nodes[endIndex]);diagramLink.Weight = distance;//设置连接的权重diagramLink.Font = new Font("宋体", 14);diagramLink.Text = distance.ToString();if (diagram1.Links.Any(x => x.Origin == diagram1.Nodes[endIndex] && x.Destination == diagram1.Nodes[startIndex])){//如果链接是双向的即←→,则设置文本为空diagramLink.Text = "";}sequence++;diagramLink.Id = sequence;diagramLink.Tag = $"【{diagram1.Nodes[startIndex].Text}】->【{diagram1.Nodes[endIndex].Text}】,权重Weight为【{distance}】";diagram1.Links.Add(diagramLink);//增加反向连线,权重Weight与正向连线一致DiagramLink reverseLink = new DiagramLink(diagram1, diagram1.Nodes[endIndex], diagram1.Nodes[startIndex]);reverseLink.Weight = distance;//设置连接的权重reverseLink.Font = new Font("宋体", 14);reverseLink.Text = distance.ToString();if (diagram1.Links.Any(x => x.Origin == diagram1.Nodes[startIndex] && x.Destination == diagram1.Nodes[endIndex])){//如果链接是双向的即←→,则设置文本为空reverseLink.Text = "";}sequence++;reverseLink.Id = sequence;reverseLink.Tag = $"【{diagram1.Nodes[startIndex].Text}】->【{diagram1.Nodes[startIndex].Text}】,权重Weight为【{distance}】";diagram1.Links.Add(reverseLink);}/// <summary>/// 初始化【权重图】或【距离图】:/// 一、初始化所有顶点,并标记所有顶点都是未访问的/// 二、初始化任意两点的距离都是无穷大的/// 三、图的实际距离【两点之间可以直接连接的部分,也就是 直接连接的顶点之间的距离 覆盖原来的默认值无穷大】/// </summary>public void InitGraph(){InitNode();//初始化最短距离为无穷大,所有矩阵距离都为无穷大for (int i = 0; i < VertexCount; i++){for (int j = 0; j < VertexCount; j++){MatrixDistance[i, j] = Infinity;}}#region 添加边Edge:图的连线部分//AB AC ADAddLink(0, 1, 5);AddLink(0, 2, 3);AddLink(0, 3, 19);//BC BEAddLink(1, 2, 10);AddLink(1, 4, 8);//CD CE CFAddLink(2, 3, 14);AddLink(2, 4, 12);AddLink(2, 5, 9);//DE DFAddLink(3, 4, 5);AddLink(3, 5, 4);//EFAddLink(4, 5, 4);#endregion#region 默认最短距离为无穷大for (int i = 0; i < VertexCount; i++){MinDistanceTuples[i] = Tuple.Create(VertexTuples[0].Item1, VertexTuples[i].Item1, Infinity, 0);}#endregion}/// <summary>/// 设置第一个顶点A到其他顶点的距离是直连的/// ①如果当前顶点A到其他顶点的距离小于Infinity,就以当前距离作为初始最小的距离/// ②找出未访问的顶点中,距离最小的顶点的顶点,然后标记顶点为已访问的/// ③如果当前节点未访问,并且 最短距离+【最短距离的顶点可到达的顶点的距离之和】,那么就设置当前路径为最小距离 需要一个双重循环/// </summary>public void GetRouterPath(){int startIndex = 0;//将第一个顶点更新为已访问VertexTuples[startIndex] = Tuple.Create(VertexTuples[startIndex].Item1, true);for (int i = 0; i < VertexCount; i++){if (MatrixDistance[startIndex, i] < MinDistanceTuples[i].Item3){//因元组无法为第三项赋值,只能重建元组了MinDistanceTuples[i] = Tuple.Create(MinDistanceTuples[i].Item1, MinDistanceTuples[i].Item2, MatrixDistance[startIndex, i], startIndex);}}for (int cnt = 1; cnt < VertexCount; cnt++){//找出最小的距离对应的顶点索引,并将当前顶点设置为已访问int minIndex = FindMinDistanceIndex();float minDist = MinDistanceTuples[minIndex].Item3;//设置为已访问该顶点VertexTuples[minIndex] = Tuple.Create(VertexTuples[minIndex].Item1, true);for (int i = 0; i < VertexCount; i++){//如果当前节点未访问,并且 最短距离+【最短距离的顶点可到达的顶点的距离之和】 还要比原来的还要短,就用新的最短距离赋值if (!VertexTuples[i].Item2 && minDist + MatrixDistance[minIndex, i] < MinDistanceTuples[i].Item3){//记录上一个最短距离顶点的索引MinDistanceTuples[i] = Tuple.Create(MinDistanceTuples[i].Item1, MinDistanceTuples[i].Item2, minDist + MatrixDistance[minIndex, i], minIndex);}}}}/// <summary>/// 显示最短路径的详细信息/// </summary>/// <param name="vertexIndex"></param>/// <returns></returns>public string DisplayDescription(int vertexIndex){return $"最短路径长度:{VertexTuples[0].Item1}->{VertexTuples[vertexIndex].Item1},最短距离{MinDistanceTuples[vertexIndex].Item3},上一个顶点索引:{MinDistanceTuples[vertexIndex].Item4}.\n" +$"  完整路由:{GetSerialPath(vertexIndex)}";}/// <summary>/// 获取连续节点路线/// </summary>/// <param name="parentIndex"></param>/// <returns></returns>private string GetSerialPath(int parentIndex){Stack<string> stack = new Stack<string>();stack.Push(VertexTuples[parentIndex].Item1);while (parentIndex != 0){parentIndex = MinDistanceTuples[parentIndex].Item4;stack.Push(VertexTuples[parentIndex].Item1);}return string.Join("->", stack);}/// <summary>/// 找出最小的距离对应的顶点索引/// </summary>/// <returns></returns>private int FindMinDistanceIndex(){//找出未访问的顶点中,距离最小的顶点的起点索引int minIndex = -1;//最小距离所在的索引float minDist = Infinity;//最小距离for (int i = 0; i < VertexCount; i++){if (!VertexTuples[i].Item2 && MinDistanceTuples[i].Item3 < minDist){minIndex = i;minDist = MinDistanceTuples[i].Item3;}}return minIndex;}private void FormDijkstraDiagram_Load(object sender, EventArgs e){InitGraph();}private async void btnGetMinRouter_Click(object sender, EventArgs e){await Task.Run(() => {Stopwatch stopwatch = new Stopwatch();stopwatch.Start();//这里最短路径算法GetRouterPath();List<string> pathRouterList = new List<string>();for (int vertexIndex = 0; vertexIndex < VertexCount; vertexIndex++){pathRouterList.Add(DisplayDescription(vertexIndex));}stopwatch.Stop();MessageBox.Show($"获取最短路径耗时:【{stopwatch.Elapsed.TotalMilliseconds}】ms", "运行耗时(ms)");MessageBox.Show($"{string.Join("\n\n", pathRouterList)}");});}}
}

运行如图:

 

相关文章:

  • 2025年SEVC SCI2区,基于强化学习的改进算术优化算法QL-REP-AOA+全局优化,深度解析+性能实测
  • n8n部署步骤
  • 【完整源码+数据集+部署教程】石材实例分割系统源码和数据集:改进yolo11-CA-HSFPN
  • 统一事件源
  • mysql知识点3--创建和使用数据库
  • WPF案例展示
  • [原创](现代Delphi 12指南):[macOS 64bit App开发]: SameText, SameStr, 比较字符串更简单
  • Boost.Timer 中的 progress_display 进度条介绍与使用
  • mac redis以守护进程重新启动
  • CppCon 2016 学习:A C++ MQTT Message Broker for the Enterprise
  • 机器学习基本概念与建模流程
  • React第六十节 Router中createHashRouter的具体使用详解及案例分析
  • 安信可(云知声蜂鸟US516P6)SDK开发学习---log日志打印子系统模块
  • 蓝桥杯等竞赛场景下 C++ 的时间与空间复杂度深度解析​
  • Python打卡第51天
  • 文献管理软件EndNote下载与安装教程(详细教程)2025最新版详细图文安装教程
  • MySQL查看连接情况
  • 力扣-347.前K个高频元素
  • (ML-Agents) 是一个开源项目,它使游戏和模拟能够作为使用深度强化学习和模仿学习训练智能代理的环境
  • 建造者模式(Builder Pattern)
  • 做网站的抬头标语怎么做/易推广
  • 手机网站编程/google关键词排名优化
  • 做网站 传视频 用什么笔记本好/友情链接交换网址大全
  • 邢台做外贸网站/推广普通话手抄报内容文字
  • 网上注册公司要多少钱/提高seo关键词排名
  • 重庆网站布局信息公司/大数据分析师