日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

C#數(shù)據(jù)結(jié)構(gòu)與算法揭秘15

 黃金屋1 2017-04-10

這節(jié),我們主要討論,一下克魯斯卡爾算法實(shí)現(xiàn) 最小生成樹。

 克魯斯卡爾算法的基本思想是:對(duì)一個(gè)有 n個(gè)頂點(diǎn)的無向連通網(wǎng),將圖中的邊按權(quán)值大小依次選取,若選取的邊使生成樹不形成回路,則把它加入到樹中;若形成回路,則將它舍     棄。如此進(jìn)行下去,直到樹中包含有 n-1條邊為止。

以下圖 (a)為例說明用克魯斯卡爾算法求無向連通網(wǎng)最小生成樹的過程。
第一步:首先比較網(wǎng)中所有邊的權(quán)值,找到最小的權(quán)值的邊(D,E),加入到生成樹的邊集 TE 中,TE={(D,E)}。
第二步:再比較圖中除邊(D,E)的邊的權(quán)值,又找到最小權(quán)值的邊(A,D)并且不會(huì)形成回路,加入到生成樹的邊集 TE 中,TE={(A,D),(D,E)}。
第三步: 再比較圖中除 TE 以外的所有邊的權(quán)值, 找到最小的權(quán)值的邊(A,B) 并且不會(huì)形成回路,加入到生成樹的邊集 TE 中,TE={(A,D),(D,E),(A,B)}。
第四步:再比較圖中除 TE 以外的所有邊的權(quán)值,找到最小的權(quán)值的邊(E,C) 并且不會(huì)形成回路,加入到生成樹的邊集 TE 中,TE={(A,D),(D,E),(A,B),(E,C)}。 此時(shí),邊集 TE 中已經(jīng)有 n-1條邊,如下圖(b) 所示。這個(gè)結(jié)果與用普里姆算法得到的結(jié)果相同。 

 

 

實(shí)現(xiàn)源代碼如下:

復(fù)制代碼
public int[] Klausi() 
    { 
        int[] lowcost = new int[nodes.Length];   //權(quán)值數(shù)組 保存權(quán)值的數(shù)組
        int[] closevex = new int[nodes.Length];  //頂點(diǎn)數(shù)組 保存 相應(yīng)各個(gè)頂點(diǎn)的數(shù)組
        int mincost = int.MaxValue;              //最小權(quán)值 默認(rèn)是 int的最大值 表示無窮大
 
        //輔助數(shù)組初始化   對(duì)摸個(gè)  權(quán)值數(shù)組賦值   保存 最小值
        for (int i = 1; i < nodes.Length; ++i) 
        { 
            lowcost[i] = matrix[0, i]; 
            closevex[i] = 0; 
        } 
 
        //某個(gè)頂點(diǎn)加入集合U 
        lowcost[0] = 0; 
        closevex[0] = 0; 
       //判斷最小的權(quán)值通過的頂點(diǎn)的循環(huán)就此開始
      for(int i=0; i<nodes.Length; ++i) 
        { 
            int k = 1; 
            int j = 1; 
 
            //選取權(quán)值最小的邊和相應(yīng)的頂點(diǎn) 
            while(j < nodes.Length) 
            { 
                if (lowcost[j] < mincost && lowcost[j] != 0) 
                { 
                    k = j; 
                } 
                ++j; 
            } 
 
            //新頂點(diǎn)加入集合U 
            lowcost[k] = 0; 
 
            //重新計(jì)算該頂點(diǎn)到其余頂點(diǎn)的邊的權(quán)值    
            for (j = 1; j < nodes.Length; ++j) 
            { 
                if (matrix[k, j] < lowcost[j]) 
                { 
                    lowcost[j] = matrix[k, j]; 
                    closevex[j] = k; 
                } 
            } 
        } 
 
        return closevex; 
  
} 
//我們明顯的看出來,由于用到了雙重循環(huán),其算法的時(shí)間的復(fù)雜度是O(n^2)
復(fù)制代碼

  介紹了最短路徑的概念

最短路徑問題是圖的又一個(gè)比較典型的應(yīng)用問題。例如,n個(gè)城市之間的一個(gè)公路網(wǎng),給定這些城市之間的公路的距離,能否找到城市 A 到城市 B 之間一條距離最近的通路呢?如果城市用頂點(diǎn)表示,城市間的公路用邊表示,公路的長度作為邊的權(quán)值。那么,這個(gè)問題就可歸結(jié)為在網(wǎng)中求頂點(diǎn) A 到頂點(diǎn) B 的所有路徑中邊的權(quán)值之和最小的那一條路徑, 這條路徑就是兩個(gè)頂點(diǎn)之間的最短路徑(Shortest Path),并稱路徑上的第一個(gè)頂點(diǎn)為源點(diǎn)(Source) ,最后一個(gè)頂點(diǎn)為終點(diǎn)(Destination) 。在不帶權(quán)的圖中,最短路徑是指兩個(gè)頂點(diǎn)之間經(jīng)歷的邊數(shù)最少的路徑。 最短路徑可以是求某個(gè)源點(diǎn)出發(fā)到其它頂點(diǎn)的最短路徑, 也可以是求網(wǎng)中任意兩個(gè)頂點(diǎn)之間的最短路徑。這里只討論單源點(diǎn)的最短路徑問題,感興趣的讀者可參考有關(guān)文獻(xiàn),了解每一對(duì)頂點(diǎn)之間的最短路徑。 網(wǎng)分為無向網(wǎng)和有向網(wǎng),當(dāng)把無向網(wǎng)中的每一條邊(vi,vj)都定義為弧<vi,vj>和弧<vj,vi>,則有向網(wǎng)就變成了無向網(wǎng)。因此,不失一般性,我們這里只討論有向網(wǎng)上的最短路徑問題。 下圖是一個(gè)有向網(wǎng)及其鄰接矩陣。該網(wǎng)從頂點(diǎn) A 到頂點(diǎn) D 有 4條路徑,分別是:路徑(A,D) ,其帶權(quán)路徑長度為 30;路徑(A,C,F,D) ,其帶權(quán)路徑長度為 22;路徑(A,C,B,E,D) ,其帶權(quán)路徑長度為 32;路徑(A,C,F,E,D) ,其帶權(quán)路徑長度為 34。路徑(A,C,F,D)稱為最短路徑,其帶權(quán)路徑長度 22稱為最短距離。 

他用的是狄克斯特拉(Dikastra)算法

對(duì)于求單源點(diǎn)的最短路徑問題,狄克斯特拉(Dikastra)提出了一個(gè)按路徑長度遞增的順序逐步產(chǎn)生最短路徑的構(gòu)造算法。狄克斯特拉的算法思想是:設(shè)置兩個(gè)頂點(diǎn)的集合 S 和T, 集合 S 中存放已找到最短路徑的頂點(diǎn), 集合 T 中存放當(dāng)前還未找到最短路徑的頂點(diǎn)。初始狀態(tài)時(shí),集合 S 中只包含源點(diǎn),設(shè)為 v0,然后從集合 T 中選擇到源點(diǎn) v0路徑長度最短的頂點(diǎn) u加入到集合 S 中,集合 S 中每加入一個(gè)新的頂點(diǎn) u都要修改源點(diǎn) v0到集合 T 中剩余頂點(diǎn)的當(dāng)前最短路徑長度值,集合 T 中各頂點(diǎn)的新的最短路徑長度值為原來的當(dāng)前最短路徑長度值與從源點(diǎn)過頂點(diǎn) u到達(dá)該頂點(diǎn)的新的最短路徑長度中的較小者。此過程不斷重復(fù),直到集合 T 中的頂點(diǎn)全部加到集合 S 中為止。

以下圖為例說明用狄克斯特拉算法求有向網(wǎng)的從某個(gè)頂點(diǎn)到其余頂點(diǎn)最短路徑的過程。

第一步:列出頂點(diǎn) A 到其余各頂點(diǎn)的路徑長度,它們分別為 0、∞、5、30、∞、∞。從中選取路徑長度最小的頂點(diǎn) C(從源點(diǎn)到頂點(diǎn) C 的最短路徑為 5) 。
第二步:找到頂點(diǎn) C 后,再觀察從源點(diǎn)經(jīng)頂點(diǎn) C 到各個(gè)頂點(diǎn)的路徑是否比第一步所找到的路徑要?。ㄒ堰x取的頂點(diǎn)則不必考慮) ,可發(fā)現(xiàn),源點(diǎn)到頂點(diǎn) B的路徑長度更新為 20(A,C,B) ,源點(diǎn)到頂點(diǎn) F 的路徑長度更新為 12(A,C,F(xiàn)) , 其余的路徑則不變。 然后, 從已更新的路徑中找出路徑長度最小的頂點(diǎn) F (從源點(diǎn)到頂點(diǎn) F 的最短路徑為 12) 。
第三步:找到頂點(diǎn) C、F 以后,再觀察從源點(diǎn)經(jīng)頂點(diǎn) C、F 到各頂點(diǎn)的路徑是否比第二步所找到的路徑要?。ㄒ驯贿x取的頂點(diǎn)不必考慮) ,可發(fā)現(xiàn),源點(diǎn)到頂點(diǎn) D 的路徑長度更新為 22(A,C,F(xiàn),D) ,源點(diǎn)到頂點(diǎn) E 的路徑長度更新為30(A,C,F(xiàn),E) ,其余的路徑不變。然后,從已更新的路徑中找出路徑長短最小的頂點(diǎn) D(從源點(diǎn)到頂點(diǎn) D 的最短路徑為 22) 。
第四步:找到頂點(diǎn) C、F、D 后,現(xiàn)在只剩下最后一個(gè)頂點(diǎn) E 沒有找到最短路徑了,再觀察從源點(diǎn)經(jīng)頂點(diǎn) C、F、D 到頂點(diǎn) E 的路徑是否比第三步所找到的路徑要?。ㄒ堰x取的頂點(diǎn)則不必考慮) ,可以發(fā)現(xiàn),源點(diǎn)到頂點(diǎn) E 的路徑長度更新為 28(A,B,E) ,其余的路徑則不變。然后,從已更新的路徑中找出路徑長度最小的頂點(diǎn) E(從源點(diǎn)到頂點(diǎn) E 的最短路徑為 28)。

、有向網(wǎng)的鄰接矩陣類的實(shí)現(xiàn)
本書以有向網(wǎng)的鄰接矩陣類 DirecNetAdjMatrix<T>來實(shí)現(xiàn)狄克斯特拉算法。DirecNetAdjMatrix<T>有三個(gè)成員字段, 一個(gè)是 Node<T>類型的一維數(shù)組 nodes,存放有向網(wǎng)中的頂點(diǎn)信息,一個(gè)是整型的二維數(shù)組 matirx,表示有向網(wǎng)的鄰接矩陣,存放弧的信息,一個(gè)是整數(shù) numArcs,表示有向網(wǎng)中弧的數(shù)目,有向網(wǎng)的鄰接矩陣類 DirecNetAdjMatrix<T>源代碼的實(shí)現(xiàn)如下所示。

復(fù)制代碼
public class DirecNetAdjMatrix<T> : IGraph<T>//繼承圖形的接口
{  
 private Node<T>[] nodes;      //頂點(diǎn)數(shù)組     存取相應(yīng)的結(jié)點(diǎn)的 泛型數(shù)組
        private int numEdges;         //邊的數(shù)目     上圖邊數(shù)字是6
        private int[,] matrix;       //鄰接矩陣數(shù)組      存取相應(yīng)的互相的權(quán)值
 
        //構(gòu)造器  進(jìn)行數(shù)據(jù)的初始化  邊的數(shù)目是0
        public NetAdjMatrix (int n) 
        { 
            nodes = new Node<T>[n]; 
            matrix = new int[n,n]; 
            numEdges = 0; 
        } 
 
        //獲取索引為index的頂點(diǎn)的信息    算法的時(shí)間復(fù)雜度是O(1)
        public Node<T> GetNode(int index) 
        { 
            return nodes[index]; 
        } 
 
        //設(shè)置索引為index的頂點(diǎn)的信息  算法的時(shí)間復(fù)雜度是O(1)
        public void SetNode(int index, Node<T> v)
       { 
         nodes[index] = v; 
       }
        //邊的數(shù)目屬性 可讀可寫的屬性 
         public int NumEdges 
         {
get 
          { 
           return numEdges; 
          } 
          set 
          {
           numEdges = value; 
          } 
         }
         //獲取matrix[index1, index2]的值 算法的時(shí)間復(fù)雜度是O(1)
         public int GetMatrix(int index1, int index2)
         {
          return matrix[index1, index2];
         }
         //設(shè)置matrix[index1, index2]的值 算法的復(fù)雜度是O(1) 
         public void SetMatrix(int index1, int index2, int v) 
         { 
           matrix[index1, index2] = v; 
         } 
          //獲取頂點(diǎn)的數(shù)目 算法的時(shí)間的復(fù)雜度是O(1)
           public int GetNumOfVertex() 
          { 
           return nodes.Length; 
          } 
          //獲取邊的數(shù)目 算法的時(shí)間的復(fù)雜度是O(1) 
        public int GetNumOfEdge() 
        {
            return numEdges;
         }
         //v是否是無向網(wǎng)的頂點(diǎn) 
         //如果包含這個(gè)頂點(diǎn)  返回為真,否則返回為假。
         //由于這是一層循環(huán),算法的復(fù)雜度是O(n)
        public bool IsNode(Node<T> v) 
        { 
            //遍歷頂點(diǎn)數(shù)組 
            foreach (Node<T> nd in nodes) 
            { 
                //如果頂點(diǎn)nd與v相等,則v是圖的頂點(diǎn),返回true 
                if (v.Equals(nd)) 
                { 
                    return true; 
                } 
            } 
 
            return false; 
        } 
 
        //獲得頂點(diǎn)v在頂點(diǎn)數(shù)組中的索引 
        //  如果相等,返回相應(yīng)的索引。
        //由于是一層循環(huán),時(shí)間的復(fù)雜度是O(n)

        public int GetIndex(Node<T> v) 
        { 
            int i = -1; 
 
            //遍歷頂點(diǎn)數(shù)組 
            for (i = 0; i < nodes.Length; ++i) 
            { 
                //如果頂點(diǎn)nd與v相等,則v是圖的頂點(diǎn),返回索引值 
                if (nodes[i].Equals(v)) 
                { 
                    return i; 
                } 
  } 
            return i; 
        } 
 
        //在頂點(diǎn)v1、v2之間添加權(quán)值為v的邊 
        //添加相應(yīng)的權(quán)值的v的邊,  這是一個(gè)對(duì)稱矩陣。

        public void SetEdge(Node<T> v1, Node<T> v2, int v) 
        { 
            //v1或v2不是無向網(wǎng)的頂點(diǎn) 
            if (!IsNode(v1) || !IsNode(v2)) 
            { 
                Console.WriteLine("Node is not belong to Graph!"); 
                return; 
            } 
 
            //矩陣是對(duì)稱矩陣 
            matrix[GetIndex(v1), GetIndex(v2)] = v; 
            matrix[GetIndex(v2), GetIndex(v1)] = v; 
            ++numEdges; 
        } 
 
        //刪除v1和v2之間的邊 
       // 刪除對(duì)稱矩陣。

        public void DelEdge(Node<T> v1, Node<T> v2) 
        { 
            //v1或v2不是無向網(wǎng)的頂點(diǎn) 
            if (!IsNode(v1) || !IsNode(v2)) 
            { 
                Console.WriteLine("Node is not belong to Graph!"); 
                return; 
            } 
 
            //v1和v2之間存在邊 
            if (matrix[GetIndex(v1), GetIndex(v2)] != int.MaxValue) 
            { 
                //矩陣是對(duì)稱矩陣 
                matrix[GetIndex(v1), GetIndex(v2)] = int.MaxValue; 
                matrix[GetIndex(v2), GetIndex(v1)] = int.MaxValue; 
                --numEdges; 
            } 
        } 
 
        //判斷v1和v2之間是否存在邊 
        //判斷相應(yīng)  不是 最大值  返回為真 否則 為假 算法的時(shí)間復(fù)雜度O(1)
        public bool IsEdge(Node<T> v1, Node<T> v2) 
        { 
            //v1或v2不是無向網(wǎng)的頂點(diǎn) 
            if (!IsNode(v1) || !IsNode(v2)) 
            { 
                Console.WriteLine("Node is not belong to Graph!"); 
                return false; 
            } 
 
            //v1和v2之間存在邊 
            if (matrix[GetIndex(v1), GetIndex(v2)] != int.MaxValue) 
            { 
                return true; 
            } 
            Else  //v1和v2之間不存在邊 
            { 
                return false; 
            } 
        } 
} 
復(fù)制代碼

為實(shí)現(xiàn)狄克斯特拉算法,引入兩個(gè)數(shù)組,一個(gè)一維數(shù)組 ShortPathArr,用來保存從源點(diǎn)到各個(gè)頂點(diǎn)的最短路徑的長度,一個(gè)二維數(shù)組 PathMatrixArr,用來保存從源點(diǎn)到某個(gè)頂點(diǎn)的最短路徑上的頂點(diǎn),如 PathMatrix[v][w]為 true,則 w從源點(diǎn)到頂點(diǎn) v 的最短路徑上的頂點(diǎn)。為了該算法的結(jié)果被其他算法使用,把這兩個(gè)數(shù)組作為算法的參數(shù)使用。另外,為了表示某頂點(diǎn)的最短路徑是否已經(jīng)找到,在算法中設(shè)了一個(gè)一維數(shù)組 final,如果 final[i]為 true,則表示已經(jīng)找到第 i 個(gè)頂點(diǎn)的最短路徑。i 是該頂點(diǎn)在鄰接矩陣中的序號(hào)。同樣,把該算法作為類DirecNetAdjMatrix<T>的成員方法來實(shí)現(xiàn)。

復(fù)制代碼
//pathMatricArr用來保存從源點(diǎn)到某個(gè)頂點(diǎn)的最短路徑上的頂點(diǎn)
//ShortPathArr用來保存從源點(diǎn)到各個(gè)頂點(diǎn)的最短路徑的長度
//n 結(jié)點(diǎn)的泛型數(shù)組
1
public void Dijkstra(ref bool[,] pathMatricArr, 2 ref int[] shortPathArr, Node<T> n) 3 { 4 int k = 0;
//結(jié)點(diǎn)是否訪問 5 bool[] final = new bool[nodes.Length]; 6 7 //初始化 8 for (int i = 0; i < nodes.Length; ++i) 9 { 10 final[i] = false; 11 shortPathArr[i] = matrix[GetIndex(n),i]; 12 13 for (int j = 0; j < nodes.Length; ++j) 14 { 15 pathMatricArr[i,j] = false; 16 } 17 if (shortPathArr[i] != 0 && shortPathArr[i] < int.MaxValue) 18 { 19 pathMatricArr[i,GetIndex(n)] = true; 20 pathMatricArr[i,i] = true; 21 } 22 } 23 24 // n為源點(diǎn) 25 shortPathArr[GetIndex(n)] = 0; 26 final[GetIndex(n)] = true; 27 28 //處理從源點(diǎn)到其余頂點(diǎn)的最短路徑 29 for (int i = 0; i < nodes.Length; ++i) 30 { 31 int min = int.MaxValue; 32 33 //比較從源點(diǎn)到其余頂點(diǎn)的路徑長度 34 for (int j = 0; j < nodes.Length; ++j) 35 { 36 //從源點(diǎn)到j(luò)頂點(diǎn)的最短路徑還沒有找到 37 if (!final[j]) 38 { 39 /從源點(diǎn)到j(luò)頂點(diǎn)的路徑長度最小 40 if (shortPathArr[j] < min) 41 { 42 k = j; 43 min = shortPathArr[j]; 44 } 45 } 46 } 47 48 //源點(diǎn)到頂點(diǎn)k的路徑長度最小 49 final[k] = true; 50 51 //更新當(dāng)前最短路徑及距離 52 for (int j = 0; j < nodes.Length; ++j) 53 { 54 if (!final[j] && (min + matrix[k,j] < shortPathArr[j])) 55 { 56 shortPathArr[j] = min + matrix[k,j]; 57 for (int w = 0; w < nodes.Length; ++w) 58 { 59 pathMatricArr[j,w] = pathMatricArr[k,w]; 60 } 61 pathMatricArr[j,j] = true; 62 } 63 } 64 } 65 }
//由于是,雙層循環(huán) 時(shí)間復(fù)雜度是O(n2)
復(fù)制代碼

如圖所示:

 當(dāng)然,圖的應(yīng)用還有很多了,點(diǎn)到為止。

至于圖的總結(jié)是:

 

 

所謂的圖是圖狀結(jié)構(gòu)簡稱圖,是另一種非線性結(jié)構(gòu),它比樹形結(jié)構(gòu)更復(fù)雜。樹形結(jié)構(gòu)中的結(jié)點(diǎn)是一對(duì)多的關(guān)系,結(jié)點(diǎn)間具有明顯的層次和分支關(guān)系。每一層的結(jié)點(diǎn)可以和下一層的多個(gè)結(jié)點(diǎn)相關(guān),但只能和上一層的一個(gè)結(jié)點(diǎn)相關(guān)。而圖中的頂點(diǎn)(把圖中的數(shù)據(jù)元素稱為頂點(diǎn))是多對(duì)多的關(guān)系,即頂點(diǎn)間的關(guān)系是任意的,圖中任意兩個(gè)頂點(diǎn)之間都可能相關(guān)。也就是說,圖的頂點(diǎn)之間無明顯的層次關(guān)系,這種關(guān)系在現(xiàn)實(shí)世界中大量存在。因此,圖的應(yīng)用相當(dāng)廣泛,在自然科學(xué)、社會(huì)科學(xué)和人文科學(xué)等許多領(lǐng)域都有著非常廣泛的應(yīng)用。例如搜索引擎,地圖等等。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多