带权邻接表图的最小生成树

如题。

在之前简单图的基础上,修改一个简单的带权邻接表图如下,备用。

class MyTable
    {
        public Node[] nodes;

        //获得图5-2所示图形,随便加了几个权值
        public static MyTable get_One_MyTable()
        {
            MyTable mtt = new();
            int n = 5;
            mtt.nodes = new Node[n];
            LinkedList<(int, int)> t;
            for (int i = 0; i < n; i++)
            {
                mtt.nodes[i] = new Node("v" + i);
            }
            t = new();
            t.AddLast((1, 10));
            t.AddLast((2, 30));
            t.AddLast((4, 50));
            mtt.nodes[0].next = t;
            t = new();
            t.AddLast((0, 10));
            t.AddLast((2, 60));
            mtt.nodes[1].next = t;
            t = new();
            t.AddLast((0, 30));
            t.AddLast((1, 60));
            t.AddLast((4, 20));
            mtt.nodes[2].next = t;
            t = new();
            t.AddLast((4, 40));
            mtt.nodes[3].next = t;
            t = new();
            t.AddLast((0, 50));
            t.AddLast((2, 20));
            t.AddLast((3, 40));
            mtt.nodes[4].next = t;
            return mtt;
        }

        public void testShow()
        {
            if (nodes == null)
            {
                Console.WriteLine("No Nodes.");
                return;
            }
            foreach (var item in nodes)
            {
                Console.Write($"节点{item.v},边:");
                foreach (var item1 in item.next)
                {
                    Console.Write(item1.Item1 + "," + item1.Item2 + "    ");
                }
                Console.WriteLine();
            }
        }
    }
    //顶点(值和指向边的指针)
    class Node
    {
        public string v;
        public LinkedList<(int, int)> next;
        public Node(string x)
        {
            v = x;
        }
    }

写一个普里姆算法辅助类,代码如下:

class PMinTree
    {
        //输入图定点状态表
            //true表示已加入树,反之未加入
        static bool[] flags;
        //准备吸入的点(起点,终点,权值)
        static Queue<(int start, int end, int power)> q = new();
        static MyTable in_g, out_g;
        public static MyTable get_Min_Tree(MyTable x)
        {
            //先做准备工作
            //结果图(out_g)先放上所有顶点,起始点状态为true,边空
            in_g = x;
            out_g = new();
            int n = in_g.nodes.Length;
            flags = new bool[n];
            out_g.nodes = new Node[n];
            for (int i = 0; i < in_g.nodes.Length; i++)
            {
                out_g.nodes[i]=new(in_g.nodes[i].v);
                out_g.nodes[i].next = new();
            }
            flags[0] = true;
            //一条临时边
            (int start, int end,int power) t_edge;

            //只要还有没加入结果的点,就一直扫描
            while(flags.Contains(false))
            {
                scan_Enqueue();
                t_edge = get_Edge();
                //把扫出来的边加到“生成树图”,也就是输出图中
                out_g.nodes[t_edge.start].next.AddLast((t_edge.end, t_edge.power));
                //注意要加两条边
                out_g.nodes[t_edge.end].next.AddLast((t_edge.start, t_edge.power));
                //加入的点状态设为true
                flags[t_edge.end] = true;
            }

            return out_g;
        }

        //扫描入队
        static void scan_Enqueue()
        {
            //扫描所有输入图中
            for (int i = 0; i < in_g.nodes.Length; i++)
            {
                //已连通的点(对应flag为true)的边
                if(flags[i])
                {
                    //取出其中通向
                    foreach (var item in in_g.nodes[i].next)
                    {
                        //未连通点(对应flag为false)的边
                        if (!flags[item.Item1])
                        {
                            //入队(入队格式:起点、终点、权值。)
                            //(因为未来加入out_g的时候需要起点终点,而权值是判断依据)
                            q.Enqueue((i, item.Item1, item.Item2));
                        }
                    }
                }
            }
        }

        //获取队列中权值最小的边
        static (int start,int end,int power) get_Edge()
        {
            (int start, int end, int power) r, t;
            if (q.Count==0)
            {
                return (-1, -1,-1);
            }
            else
            {
                r = q.Dequeue();
                while(q.Count>0)
                {
                    t = q.Dequeue();
                    if(t.power<r.power)
                    {
                        r = t;
                    }
                }
                return r;
            }
        }
    }

主程序调用:

static void Main(string[] args)
        {
            MyTable a, b;
            a = MyTable.get_One_MyTable();
            b = PMinTree.get_Min_Tree(a);
            a.testShow();
            Console.WriteLine("----------------------------");
            b.testShow();
        }

 运行结果:

节点v0,边:1,10    2,30    4,50
节点v1,边:0,10    2,60
节点v2,边:0,30    1,60    4,20
节点v3,边:4,40
节点v4,边:0,50    2,20    3,40
----------------------------
节点v0,边:1,10    2,30
节点v1,边:0,10
节点v2,边:0,30    4,20
节点v3,边:4,40
节点v4,边:2,20    3,40

验证正确。

原文地址:https://www.cnblogs.com/wanjinliu/p/14042673.html