最小生成树

基本概念

  • 生成树:设G为连通网,具有G的所有顶点(假设为n个)且只有n-1条边的连通子网。
  • 树的权:生成树T的各边的权值的和。
  • 最小生成树:权值最小的生成树。

Prim算法

算法描述:
在这里插入图片描述

    public class SpanTreeNode//最小生成树的结点
    {
        public string ParentName { get; }//双亲节点的名称
        public string SelfName { get; }//自己的名称
        public double Weight { get; set; }//父结点到双亲结点的路径的权值
        public SpanTreeNode(string selfname, string parentname, double weight)
        {
            if (string.IsNullOrEmpty(selfname) || string.IsNullOrEmpty(parentname))
            {
                throw new ArgumentNullException();
                //此处最小生成树中的结点的名字不能为空,但是图的顶点名字可以为空。
            }
            ParentName = parentname;
            SelfName = selfname;
            Weight = weight;
        }
    }

        //贪心算法,不一定是最优
        public SpanTreeNode[] MiniSpanTree(string vName)//从Vname这个结点开始构造最小生成树
        {
            int i = GetIndex(vName);
            if (i == -1)
            {
                return null;
            }

            SpanTreeNode[] SpanTree = new SpanTreeNode[VertexCount];//最小生成树
            SpanTree[0] = new SpanTreeNode(vName, "Null", 0.0);

            //记录U中的结点(并非特指一个,重点在于权值最小)到V-U中各个结点最小权值对应的那个结点的index
            //vertexIndex中的下标对应的是U中的结点,即记录父结点
            int[] vertexIndex = new int[VertexCount];
            //记录U中结点(泛指)到V-U中各结点的最小权值。下标代表V中结点的index
            double[] LowCost = new double[VertexCount];
            for (int j = 0; j < VertexCount; j++)
            {
                vertexIndex[j] = i;
                LowCost[j] = double.MaxValue;
            }
            EdgeNode p1 = _vertexList[i].FirstNode;
            while (p1 != null)
            {
                LowCost[p1.Index] = p1.Weight;
                p1 = p1.Next;
            }
            vertexIndex[i] = -1;//vertexIndex=-1代表这个点已经是U中的点
            //找出与U中结点相连的权值最小的V-U中的结点以及最小权值
            for (int count = 1; count < VertexCount; count++)
            {
                double min = double.MaxValue;//最小权值
                int v = i;//最小权值对应的V-U中的结点
                for (int k = 0; k < VertexCount; k++)
                {
                    if (vertexIndex[k] != -1 && min > LowCost[k])
                    {
                        min = LowCost[k];
                        v = k;
                    }
                }
                SpanTree[count] = new SpanTreeNode(_vertexList[v].VertexName,
                    _vertexList[vertexIndex[v]].VertexName, min);
                vertexIndex[v] = -1;//v这个结点已经是U中的结点

                EdgeNode temp = _vertexList[v].FirstNode;
                while (temp != null)
                {
                    if (vertexIndex[temp.Index] != -1 && LowCost[temp.Index] > temp.Weight)
                    {
                        LowCost[temp.Index] = temp.Weight;
                        vertexIndex[temp.Index] = v;
                    }
                    temp = temp.Next;
                }
            }
            return SpanTree;
        }

Kruskar算法(全局最优)

在这里插入图片描述难点:不同的连通分量如何体现
通过记录父结点的数组找出始祖。

        //Kruskar算法(全局最优)
        //首先构造边的集合(按照权重由小到大的顺序)
    public class Edge
    {
        public int Begin { get; }
        public int End { get; }
        public double Weight { get; }
        public Edge(int begin, int end, double weight)
        {
            Begin = begin;
            End = end;
            Weight = weight;
        }
    }
        public Edge[] GetEdges()
        {
            //边不可重复,(u,v)=(v,u)
            for (int i = 0; i < VertexCount; i++)
            {
                _vertexList[i].Visited = false;
            }
            //List实际上是动态数组
            List<Edge> result = new List<Edge>();//不知道一共有多少条边
            for (int i = 0; i < VertexCount; i++)
            {
                EdgeNode temp = _vertexList[i].FirstNode;
                while (temp != null)
                {
                    if (_vertexList[temp.Index].Visited == false)
                    {
                        result.Add(new Edge(i, temp.Index, temp.Weight));
                    }
                    temp = temp.Next;
                }
                _vertexList[i].Visited = true;
            }
            return result.OrderBy(a => a.Weight).ToArray();//a代表result里面的元素
        }
        private int FindAncestor(int[] parent, int f)//找出标号为f的结点的祖先(始祖)
        {
            while (parent[f] > -1)
            {
                f = parent[f];
            }
            return f;//无论如何不会返回-1
        }
        public SpanTreeNode[] MiniSpanTree()
        {
            int[] parent = new int[VertexCount];
            for (int i = 0; i < VertexCount; i++)
            {
                parent[i] = -1;
            }

            Edge[] edge = GetEdges();
            SpanTreeNode[] tree = new SpanTreeNode[VertexCount];
            int count = 1;
            for (int i = 0; i < edge.Length; i++)
            {
                int begin = FindAncestor(parent, edge[i].Begin);
                int end = FindAncestor(parent, edge[i].End);
                if (begin != end)//这条边的起点和终点不在同一个连通分量上
                {
                    parent[end] = begin;//关键点
                    tree[count] = new SpanTreeNode(_vertexList[edge[i].End].VertexName,
                        _vertexList[edge[i].Begin].VertexName, edge[i].Weight);
                    count++;
                }
            }
            for (int i = 0; i < VertexCount; i++)
            {
                if (parent[i] == -1)
                {
                    tree[0] = new SpanTreeNode(_vertexList[i].VertexName, "Null", 0.0);
                }
            }
            return tree;
        }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奇迹luanluan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值