单源最短路径-邻接表无向网络

如题。

例图如下:

借用之前“简单图” 的代码生成图,并进行修改和补充。

图顶点代码:

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:Hc1ConsoleApp1ConsoleApp11.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}	");
                }
                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
原文地址:https://www.cnblogs.com/wanjinliu/p/14175857.html