namespace Tnb.Common.Utils { /// /// 迪杰斯特拉(最短路径算法) /// public class Dijkstra { public static int MAX = int.MaxValue; public int mEdgNum; // 边的数量 public VNode[] mVexs; // 顶点数组 private EData[] edges; //边的数组 /* * 创建图 * * 参数说明: * vexs -- 顶点数组 * edges -- 边 */ public Dijkstra(string[] vexs, EData[] edges) { this.edges = edges; // 初始化"顶点数"和"边数" int vlen = vexs.Length; int elen = edges.Length; // 初始化"顶点" mVexs = new VNode[vlen]; for (int i = 0; i < mVexs.Length; i++) { mVexs[i] = new VNode(); mVexs[i].data = vexs[i]; mVexs[i].firstEdge = null; } // 初始化"边" mEdgNum = elen; for (int i = 0; i < elen; i++) { // 读取边的起始顶点和结束顶点 string c1 = edges[i].start; string c2 = edges[i].end; int weight = edges[i].weight; // 读取边的起始顶点和结束顶点 int p1 = GetPosition(c1); int p2 = GetPosition(c2); // 初始化node1 ENode node1 = new ENode(); node1.ivex = p2; node1.weight = weight; // 将node1链接到"p1所在链表的末尾" if (p1 != -1) { if (p1 != -1 && mVexs[p1].firstEdge == null) mVexs[p1].firstEdge = node1; else LinkLast(mVexs[p1].firstEdge, node1); } //// 初始化node2 //ENode node2 = new ENode(); //node2.ivex = p1; //node2.weight = weight; //// 将node2链接到"p2所在链表的末尾" //if (mVexs[p2].firstEdge == null) // mVexs[p2].firstEdge = node2; //else // LinkLast(mVexs[p2].firstEdge, node2); } } /* * 将node节点链接到list的最后 */ private void LinkLast(ENode list, ENode node) { ENode p = list; while (p.nextEdge != null) p = p.nextEdge; p.nextEdge = node; } /* * 返回ch位置 */ private int GetPosition(string ch) { for (int i = 0; i < mVexs.Length; i++) if (mVexs[i].data == ch) return i; return -1; } /* * 获取边的权值;若start和end不是连通的,则返回无穷大。 */ private int GetWeight(int start, int end) { if (start == end) return 0; ENode node = mVexs[start].firstEdge; while (node != null) { if (end == node.ivex) return node.weight; node = node.nextEdge; } return MAX; } /* * Dijkstra最短路径。 * 即,统计图中"起点D"到其它各个顶点的最短路径。 * * 参数说明: * vs -- 起始顶点(start vertex)。 * prev -- 前驱顶点数组。即,prev[i]的值是"起点D"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。 * dist -- 长度数组。即,dist[i]是"起点D"到"顶点i"的最短路径的长度。 */ public void CalcDijkstra(int vs, int[] prev, int[] dist) { //List vertexs = new(); //最短路径串联的点位列表 // flag[i]=true表示"起点D"到"顶点i"的最短路径已成功获取。 bool[] flag = new bool[mVexs.Length]; // 初始化 for (int i = 0; i < mVexs.Length; i++) { flag[i] = false; // 顶点i的最短路径还没获取到。 prev[i] = 0; // 顶点i的前驱顶点为0。 dist[i] = GetWeight(vs, i); // 顶点i的最短路径为"起点D"到"顶点i"的权。 } // 对"起点D"自身进行初始化 flag[vs] = true; dist[vs] = 0; HashSet set = new(); // 遍历mVexs.Length-1次;每次找出一个顶点的最短路径。 int k = 0; for (int i = 1; i < mVexs.Length; i++) { // 寻找当前最小的路径 // 即,在未获取最短路径的顶点中,找到离起点D最近的顶点(k)。 int min = MAX; for (int j = 0; j < mVexs.Length; j++) { if (flag[j] == false && dist[j] < min) { min = dist[j]; k = j; set.Add(j); } } // 标记"顶点k"为已经获取到最短路径 flag[k] = true; // 更新当前最短路径和前驱顶点 // 即,更新"未获取最短路径的顶点的最短路径和前驱顶点"。 for (int j = 0; j < mVexs.Length; j++) { int tmp = GetWeight(k, j); tmp = (tmp == MAX ? MAX : (min + tmp)); // 防止溢出 if (flag[j] == false && (tmp < dist[j])) { dist[j] = tmp; prev[j] = k; } } } } } /// /// 邻接表中表对应的链表的顶点 /// public class ENode { /// /// 该边所指向的顶点的位置 /// public int ivex; // 该边所指向的顶点的位置 /// /// 该边的权 /// public int weight; // 该边的权 /// /// 指向下一条弧的指针 /// public ENode nextEdge; // 指向下一条弧的指针 } /// /// 邻接表中表的顶点 /// public class VNode { public string data; // 顶点信息 public ENode firstEdge; // 指向第一条依附该顶点的弧 } /// /// 边的结构体 /// public class EData { public string start; // 边的起点 public string end; // 边的终点 public int weight; // 边的权重 public EData(string start, string end, int weight) { this.start = start; this.end = end; this.weight = weight; } } }