1. 程式人生 > >C#實現最小生成樹

C#實現最小生成樹

 第一種:

 //求最小生成樹,普里姆演算法(Prim)
//先給定一個初始點,然後找到離它最近的點,並加入找的點序列,將其對應的距離設為0
//然後找其它頂點距離新的找到點集合最小的點,再加入找到的點序列
//重複以上過程
public static void Prim_MiniTree(Graph g)
{
       //存放找到的點
       string[] label_checked = new string[g.nums];
        //存放最短距離,是動態變化的,第n個位置記錄的是第n個點到當前點的最短距離
       int[] lowest_length = new int[g.nums];


            //設定初始點,設定初始點到其他的距離


            label_checked[0] = g.ver[0].label;
            lowest_length[0] = 0;
            for (int j = 1; j < g.nums; j++)
            {
                lowest_length[j] = g.adjMatrix[0, j];
                label_checked[j] = " ";
            }
            Console.WriteLine(label_checked[0].ToString() + " 0 0");

            //迴圈找其他點的最短距離
            int sum = 0;
            for (int i = 1; i < g.nums; i++)
            {
                int min = 100000, k = 0;
                //先找此點到其他點的最短距離,並記錄下是哪個點
                for (int j = 0; j < g.nums; j++)
                {
                    if (lowest_length[j] != 0 && lowest_length[j] < min)

                    {
                        min = lowest_length[j];//得到距離向量中的最短值
                        k = j;//第幾個最短
                        label_checked[j] = g.ver[j].label;
                    }
                }


                //列印節點
                sum += min;
                Console.WriteLine(label_checked[k].ToString()+" "+k.ToString()+" "+min.ToString());
                lowest_length[k] = 0;//代表這個點已經找到了

                //再次迴圈,更新其他點到已經找到點距離
                for (int j = 1; j < g.nums;j++ )
                {
                    if(lowest_length[j]!=0&&lowest_length[j]>g.adjMatrix[k,j])
                    {
                      lowest_length[j]=g.adjMatrix[k,j];//更新值
                    }
                }
            }
            Console.WriteLine("\n最小生成樹的最短距離為:"+sum.ToString());
        }

第二種:克魯斯卡爾演算法:

1.將鄰接矩陣初始化為;起點、終點、邊的型別,並且將其按照邊的由小到大的順序排序;

2.初始化一個一維陣列,下邊表示起點,對應值表示終點,並寫一個用於判斷是否有環的函式,就是根據這個一維陣列,不斷變換起始點,看看是否有環;

3.遍歷邊的集合,滿足時輸出

//返回:起點、終點、權重矩陣

        public static int[,] Get_Metrix(Graph g, int nums)
        {
            int[,] a = new int[nums, 3];
            int index = 0;
            for (int i = 0; i < g.nums - 1; i++)
            {
                for (int j = i; j < g.nums; j++)
                {
                    if (g.adjMatrix[i, j] != 0 && g.adjMatrix[i, j] != 10000)
                    {
                        a[index, 0] = i;
                        a[index, 1] = j;
                        a[index, 2] = g.adjMatrix[i, j];
                        index++;
                    }
                }
            }


            //氣泡排序
            for (int i = 0; i < 15; i++)
            {
                for (int j = 0; j < 15 - 1 - i; j++)
                {
                    if (a[j, 2] > a[j + 1, 2])
                    {
                        int tmp = a[j, 2];
                        a[j, 2] = a[j + 1, 2];
                        a[j + 1, 2] = tmp;


                        tmp = a[j, 0];
                        a[j, 0] = a[j + 1, 0];
                        a[j + 1, 0] = tmp;


                        tmp = a[j, 1];
                        a[j, 1] = a[j + 1, 1];
                        a[j + 1, 1] = tmp;
                    }
                }
            }


            return a;
        }
        public static int Find_YesOrNo_Circle(int[] m, int a)
        {
            while (m[a] > 0)
            {
                a = m[a];
            }
            return a;
        }
        //克魯斯卡爾(Kruskal)演算法
        public static void Kruskal(Graph g, int nums)
        {
            int[,] Start_End_Weights = Get_Metrix(g, nums);//將鄰接矩陣轉化一下
            int[] Labels = new int[g.nums];
            for (int i = 0; i < Labels.Length; i++) //賦上初始值
            {
                Labels[i] = 0;
            }
            for (int i = 0; i < nums; i++)  //遍歷每一條邊
            {
                int start = Find_YesOrNo_Circle(Labels, Start_End_Weights[i, 0]);//找到這個起點最遠連通到哪個點
                int end = Find_YesOrNo_Circle(Labels, Start_End_Weights[i, 1]);//找到這個終點最遠連通到哪個頂點
                if (start != end) //若兩個點的終點不同
                { 
                    Labels[start] = end; //將其記入標記中
                    Console.WriteLine(Start_End_Weights[i, 0].ToString() + "-》" + Start_End_Weights[i, 1].ToString() + "  :  " + Start_End_Weights[i, 2]);
                }
            }
        }