單源最短路徑-鄰接表無向網路
阿新 • • 發佈:2020-12-23
如題。
例圖如下:
借用之前“簡單圖”的程式碼生成圖,並進行修改和補充。
圖頂點程式碼:
class Node { public string v; public LinkedList<Edge> next; public Node(string x) { v = x; } }
圖的邊程式碼:
class Edge { public int index; public int edge_weight;public Edge(int x,int y) { index = x; edge_weight = y; } }
新建一個節點類Node1,用於儲存結果:
class Node1 { //到頂點的最短路徑。減100是防止運算的時候越界 //因為圖中最大的邊權值也不到100 public int path_value=int.MaxValue-100; //通往最短路徑的上一個節點 public int pre_node = -1; }
圖類程式碼:
class MyTable { Node[] nodes; //構造方法2,獲得邊長為n的任意無向圖 public MyTable(int n) { LinkedList<Edge> t; int j,k; StreamReader sr = new StreamReader(@"C:\Hc\1\ConsoleApp1\ConsoleApp1\1.txt", Encoding.Default);if (n == -1) { Console.WriteLine("輸入圖中節點的個數:"); n = int.Parse(Console.ReadLine()); } nodes = new Node[n]; Console.WriteLine("輸入每個節點的名稱(每個名稱回車結束)"); for (int i = 0; i < n; i++) { nodes[i] = new Node(sr.ReadLine()); } for (int i = 0; i < n; i++) { Console.WriteLine($"輸入節點{nodes[i].v}的邊(序號表示,每個序號回車,-1結束)"); j = int.Parse(sr.ReadLine()); Console.WriteLine($"輸入該邊的路徑權值"); k = int.Parse(sr.ReadLine()); t = new(); do { t.AddLast(new Edge(j,k)); j = int.Parse(sr.ReadLine()); k = int.Parse(sr.ReadLine()); } while (j != -1); nodes[i].next = t; } } //按構造輸入的方式輸出圖,測試用。 public void testShow() { foreach (var item in nodes) { Console.Write($"節點{item.v},邊:"); foreach (var item1 in item.next) { Console.Write($"{nodes[item1.index].v},路徑長度:{item1.edge_weight}\t"); } Console.WriteLine(); } } //獲取指定節點的單源最短路徑 //思路:遍歷(用頂點陣列遍歷)所有節點,填入最短路徑資訊,直到再無變化為止。 public Node1[] get_Shortest_Path(int index) { //初始化 Node1[] b = new Node1[nodes.Length]; bool has_changed; int t; for (int i = 0; i < b.Length; i++) { b[i] = new Node1(); } b[index].path_value = 0; b[index].pre_node = index; //操作開始 do { //假設這一次遍歷沒有變化 has_changed = false; //遍歷所有頂點 for (int i = 0; i < nodes.Length; i++) { //對遍歷到的頂點,考察它所有的連線點和邊 foreach (var item in nodes[i].next) { //計算該邊到源點的最短路徑+這條邊的路徑,記為t t = b[item.index].path_value + item.edge_weight; //如果t小於原來記錄的最短路徑 if (t<b[i].path_value) { //則重新整理該頂點資訊 b[i].pre_node = item.index; b[i].path_value = t; has_changed = true; } } } } while (has_changed); //操作結束 //返回 return b; } //輸出最短路徑陣列 public void print_ShortPath(Node1[] x) { for (int i = 0; i < x.Length; i++) { Console.WriteLine($"節點:{nodes[i].v},前驅節點:{nodes[x[i].pre_node].v},路徑損耗:{x[i].path_value}"); } } }
為了節約除錯時間,新建了一個檔案“1.txt”,裡面放了初始化圖的輸入。
內容如下:
a b c d e f 2 14 4 9 5 7 -1 -1 2 9 3 6 -1 -1 0 14 4 2 1 9 -1 -1 5 15 4 11 1 6 -1 -1 2 2 0 9 5 10 3 11 -1 -1 0 7 4 10 3 15 -1 -1
主方法呼叫:
static void Main(string[] args) { int n = 6; MyTable a = new(n); a.testShow(); Console.WriteLine("請輸入最短路徑起點編號(整數):"); n = int.Parse(Console.ReadLine()); a.print_ShortPath(a.get_Shortest_Path(n)); }
執行結果:
節點a,邊:c,路徑長度:14 e,路徑長度:9 f,路徑長度:7 節點b,邊:c,路徑長度:9 d,路徑長度:6 節點c,邊:a,路徑長度:14 e,路徑長度:2 b,路徑長度:9 節點d,邊:f,路徑長度:15 e,路徑長度:11 b,路徑長度:6 節點e,邊:c,路徑長度:2 a,路徑長度:9 f,路徑長度:10 d,路徑長度:11 節點f,邊:a,路徑長度:7 e,路徑長度:10 d,路徑長度:15 請輸入最短路徑起點編號(整數): 1 節點:a,前驅節點:e,路徑損耗:20 節點:b,前驅節點:b,路徑損耗:0 節點:c,前驅節點:b,路徑損耗:9 節點:d,前驅節點:b,路徑損耗:6 節點:e,前驅節點:c,路徑損耗:11 節點:f,前驅節點:e,路徑損耗:21