记录一次失败的prim算法【c#】耗时6个钟

本文记录了一次尝试使用C#实现Prim算法时遇到的问题,算法应用于寻找图的最小生成树。作者在实现过程中遇到了错误,导致输出结果不正确。错误表现为遍历顺序错误,将同一顶点重复加入到最小生成树中。文章详细展示了顺序表、Edge类以及Prim算法类的代码,并附带了程序运行实例,旨在通过分析错误帮助读者理解和避免类似问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
上面是题目:实际上的结果应该是
A E D C B G F

…我又算错了,这次的错误显示在,他已经遍历到了
A A E D C D

在这里插入图片描述

首先是我自己之前制作的 顺序表 seqList 接口就不写了直接 放功能

private T[] datas;
            private int ListLength;
            private int ListSize;
            //private int index;//序号 虽然不知道有没有用

            public seqList(int size)
            {
                ListSize = size;
                datas = new T[ListSize];
                ListLength = 0;

            }

            public seqList()
            {
            }

            public void getMinEdge()
            {
            throw new NotImplementedException();
             }
            public void ClearList()
            {
                ListLength = 0;
            }
            
            public int GetLenth()
            {
                return ListLength;
            }

            public bool IsEmpty()
            {
                return ListLength == 0;
            }
            public void ListInsert(T item, int index)
            {
               if (!IsFull())
                {
                    for (int i = ListSize - 2; i >= index; i--)/
                    {
                        datas[i + 1] = datas[i];//这个循环被跳过了
                    }
                    datas[index] = item;
                    ListLength++;
                }
            }
            public void Pop(T item)
           {
              if (ListLength < ListSize)
             {
                datas[ListLength] = item;
                ListLength++;
             }
           }
            public T Peek(int index)
              {
                return datas[index];
              }
            

然后是边 Edge的类

class Edge
    {
        //边的属性需要哪些参数,首先是需要A点,其次是需要B点
        //还需要这些边的权值,最后是bool值
        public int NodeIndexA;
        public int NodeIndexB;
        public int edgeValue;
        public bool isSelected;

        public Edge(int indexA,int indexB,int value)
        {
            NodeIndexA = indexA;
            NodeIndexB = indexB;
            edgeValue = value;
            isSelected = false;
        }

接下来就是prim算法的类,这个类是我之前自己制作图的类,
不过我把默认所有无向图最开始的值设置为了50(比其余所有的值都要大)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 图csharp
{
    class myPic : iPic
    {
        private int Capacity;
        private int NodeCount;
        Queue<int> GDdata = new Queue<int>();//把看见的边都存起来;
        public int seqNodeCount;
        private int[] array;//邻接矩阵
        private picNode[] NodeArray;

        //普里姆树所需要的  顺序表
        public seqList<picNode> seqNodeLists;//备用点
        public seqList<Edge> seqEdgeLists;//备用边储存
        public seqList<picNode> MinNodeList;//最小的点
        public seqList<Edge> SelectMindEdgeLists;//最终找到的边

        //primTree所需要的参数
         //我们还需要一个存放所有结点的数组  SeqNodeLists
        //我们还需要一个存放全部不需要的边的数组,seqEdgeLists
        //需要一个存放最终最小边的数组  SelectMinEdgeLists
        //需要一个存放最终结点以及顺序数组  MinNodeList;
       

        //普里姆生成树
        public void primTree(int nodeIndex)
        {   //一直到最后被选择的边Edge 已经有 (点-1)条,结束循环
            if (SelectMindEdgeLists.GetLenth() != Capacity - 1)
            {          // 遍历7次,包括自己,因为所有值的初始值我设置为了50(比所有权值大)
                for (int i = 0; i < seqNodeLists.GetLenth(); i++) 
                {
                    int MinValue = getValueFromArray(nodeIndex, i);
                    int MinIndex = i;


                    //没有去除重复的,无向边,导致错误

                    Edge edge = new Edge(nodeIndex, i, MinValue);                            
                    seqEdgeLists.Pop(edge);//把当前nodeIndex所有的边存储起来
                }

                int minEdge = seqEdgeLists.Peek(0).edgeValue;//取出第一条边的权值
                int minEdgeIndex = default(int); //以及最小权值边所在的结点A  
                int minEdgeIndexB = default(int); //以及最小权值边的结点B
                int DeletePoint = default(int);   //记录这条最小权值边所在seq中的位置。

                for (int i = 1; i < seqEdgeLists.GetLenth() - 1; i++) //第一条已取走
                {
                    for (int j = 0; j < MinNodeList.GetLenth(); j++)
                    {//比较最小权值之前,必须确认这个最小权值边
                     //左右两个结点不能都在最终所选结点里
                     //第一次遍历时,最终所选结点中没有元素,第二次将有第一次的nodeIndex
                    
                    
                     if (seqEdgeLists.Peek(i).NodeIndexA == MinNodeList.Peek(j).Data && 
                     seqEdgeLists.Peek(i).NodeIndexB == MinNodeList.Peek(j).Data)
                        {continue;}
                     else
                     {      //如果有权重值更小的,替换掉
                            if (minEdge >= seqEdgeLists.Peek(i).edgeValue)
                            {  
                                minEdge = seqEdgeLists.Peek(i).edgeValue;//记录值
                                DeletePoint = i;                 //记录所在点,方便删除
                                
                                minEdgeIndex=seqEdgeLists.Peek(i).NodeIndexA;
                                minEdgeIndexB=seqEdgeLists.Peek(i).NodeIndexB;
                                //第一种情况,一个点是nodeIndex,第二个点是新点
                                //第二种情况,因为无向边重复了两次,反过来被选择了
                                //第三种情况,只有一个是已有的点,但不是本次循环的起点
                            }
                            else { continue; }
                        }
                        else { continue; }
                    }}
                }
                //那么在这个循环结束之后,我得到的是最小的权值 以及他相应的结点

                Edge SelectMinEdge = new Edge(minEdgeIndex, minEdgeIndexB, minEdge);
                //把这个最小边找到,放入最小边的集合。
                SelectMindEdgeLists.Pop(SelectMinEdge);   //放进去               
                seqEdgeLists.ListDelete(DeletePoint);     //在池子中把他删掉


                //无论如何,必须要有一个点是当前有的,另外一个是当前没有的
                


                    //寻找新的结点开始遍历
                    int NewnodeIndex = minEdgeIndex;
                    //把本次循环的结点放入最小结点的集合里面
                    MinNodeList.Pop(seqNodeLists.Peek(nodeIndex));

                    primTree(NewnodeIndex);

            }
        }




        public void SetSeqList()
        {
            seqNodeLists = new seqList<picNode>(Capacity);
            seqEdgeLists = new seqList<Edge>(Capacity * Capacity);
            MinNodeList = new seqList<picNode>(Capacity);
            SelectMindEdgeLists = new seqList<Edge>(Capacity - 1);
        }

        private int getValueFromArray(int row, int col)
        {
            if (row < 0 || row >= Capacity)
            { return default(int); }
            if (col < 0 || col >= Capacity)
            { return default(int); }

            int temp = array[row * Capacity + col];
            return temp;
        }
        public myPic(int capacity)
        {
            NodeCount = 0;

            Capacity = capacity;
            seqNodeCount = 0;
            //  NodeArray = new picNode[capacity];//设置结点的数组
            seqList<picNode> seqNodeLists = new seqList<picNode>(capacity);//换成自己的数组

            array = new int[capacity * capacity];//设置数据的数组
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = 50;

            }

        }
        public void AddNode(picNode node)
        {   //结点矩阵中的 结点数据等于 输入数据
            //NodeArray[NodeCount] = node;
            //NodeCount++;

            seqNodeLists.ListInsert(node, seqEdgeLists.GetLenth());





        }
        public void DeleteNode(int nodeIndex)
        {
            for (int i = 0; i < NodeCount - nodeIndex - 1; i++)
            {
                NodeArray[nodeIndex] = NodeArray[nodeIndex + 1];//后面一个位置的数字会变成前面一个

            }//在最后数组被减干净之后
            NodeCount--;
        }

        public void breadthFirstTraverse(int nodeIndex)//但是得先设置个数组int 存放广度数据
        {//广度优先遍历//先从根结点访问干净 然后访问下一个结点
            int value = 0;

            Console.Write(seqNodeLists.Peek(nodeIndex).Data + " ");
            seqNodeLists.Peek(nodeIndex).ChangeVisited(true);


            for (int i = 0; i < Capacity; i++)
            {
                value = getValueFromArray(nodeIndex, i);//取得值
                if (value == 1)//找到b了 // 输出b   //找下一个 // 弄个队列 先进的先出
                {
                    if (seqNodeLists.Peek(nodeIndex).isVisited == false)
                    {
                        GDdata.Enqueue(i);//把找到的数据放进  队列 我在外面自己set的队列
                    }
                    else
                    {
                        continue;
                    }
                }
                else//当value = 0的时候
                {
                    continue;
                }
            }
            //遍历之后
            if (GDdata.Count > 0)
            {
                breadthFirstTraverse(GDdata.Dequeue());
            }


        }

        public void depthFirstTraverse(int nodeIndex)
        {//深度遍历 先访问根  // 首先这个nodeIndex 是什么意思 是从哪里开始吗
            int value; ;
            //这里是会进行 NodeArray【length】次的遍历
            Console.Write(seqNodeLists.Peek(nodeIndex).Data + " ");
            seqNodeLists.Peek(nodeIndex).ChangeVisited(true);

            for (int i = 0; i < Capacity; i++)
            {   //我彻底 明白了 所以当 我的序列为0 时 自动搜索第0行的全部元素
                value = getValueFromArray(nodeIndex, i);
                if (value == 1)//证明搜到1,是无向图,可以继续下去
                {
                    if (seqNodeLists.Peek(nodeIndex).isVisited == true)
                    { continue; }
                    else
                    { depthFirstTraverse(i); }

                }
                else
                {
                    continue;
                }

            }


        }

        public void printMatrix()
        {
            for (int i = 0; i < Capacity; i++)
            {
                for (int k = 0; k < Capacity; k++)
                {
                    Console.Write(array[i * Capacity + k]);
                    Console.Write("       ");
                }
                Console.WriteLine();
            }
        }

        public void resetNode()
        {
            for (int i = 0; i < seqNodeLists.GetLenth(); i++)
            {
                // NodeArray[i].ChangeVisited(false);
                seqNodeLists.Peek(i).ChangeVisited(false);
            }
        }

        public bool SetValueToMatrixForDirectedGraph(int row, int col, int val)
        {//把数值 关系 复制到 有向图中   // row 行 col 列
            if (row < 0 || row >= Capacity)
            { return false; }
            if (col < 0 || col >= Capacity)
            { return false; }
            array[row * Capacity + col] = val;
            return true;
        }

        public bool SetValueToMatrixForUndiretedGraph(int row, int col, int val)
        {
            if (row < 0 || row >= Capacity)
            { return false; }
            if (col < 0 || col >= Capacity)
            { return false; }
            array[row * Capacity + col] = val;
            array[col * Capacity + row] = val;
            return true;
        }

        public void setGDdate()
        {
            Queue<int> GDdata = new Queue<int>(Capacity);
        }


    }
}

最后是我运行的程序。

namespace 图csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            myPic myPic = new myPic(7);
            myPic.SetSeqList();
            //先做结点
            picNode nodeA = new picNode('A');
            picNode nodeB = new picNode('B');
            picNode nodeC = new picNode('C');
            picNode nodeD = new picNode('D');
            picNode nodeE = new picNode('E');
            picNode nodeF = new picNode('F');
            picNode nodeG = new picNode('G');

            myPic.seqNodeLists.Pop(nodeA);
            myPic.seqNodeLists.Pop(nodeB);
            myPic.seqNodeLists.Pop(nodeC);
            myPic.seqNodeLists.Pop(nodeD);
            myPic.seqNodeLists.Pop(nodeE);
            myPic.seqNodeLists.Pop(nodeF);
            myPic.seqNodeLists.Pop(nodeG);

            myPic.SetValueToMatrixForUndiretedGraph(0, 1,19);//A连B
            myPic.SetValueToMatrixForUndiretedGraph(0, 4,14);
            myPic.SetValueToMatrixForUndiretedGraph(0, 6,18);
            myPic.SetValueToMatrixForUndiretedGraph(1, 2, 5);
            myPic.SetValueToMatrixForUndiretedGraph(1, 3, 7);
            myPic.SetValueToMatrixForUndiretedGraph(1, 4,12);
            myPic.SetValueToMatrixForUndiretedGraph(2, 3, 3);
            myPic.SetValueToMatrixForUndiretedGraph(3, 4, 8);
            myPic.SetValueToMatrixForUndiretedGraph(3, 5,21);
            myPic.SetValueToMatrixForUndiretedGraph(4, 6,16);
            myPic.SetValueToMatrixForUndiretedGraph(5, 6,27);


            myPic.printMatrix();

            myPic.primTree(0);

            for (int i = 0; i < myPic.MinNodeList.GetLenth(); i++)
            {
                Console.WriteLine(myPic.MinNodeList.Peek(i).Data);
            }

            for (int i = 0; i < myPic.SelectMindEdgeLists.GetLenth(); i++)
            {
                Console.WriteLine(myPic.SelectMindEdgeLists.Peek(i).edgeValue);
            }


            Console.ReadKey();


        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值