拓撲排序演算法的一個應用

來源:互聯網
上載者:User

在Visual Studio .NET中,一個解決方案可以包含多重專案,一個項目可以引用若干其它項目。編譯的時候,VS會自動確定每個項目的編譯順序。VS究竟是如何計算出這個順序的呢?

如果學習過資料結構,可以很容易回答出這個問題:拓撲排序(Topological Sort)。

 

什麼是拓撲排序?讓我們來溫習一下。百度百科上的介紹如下:
對一個有向非循環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若<u,v> ∈E(G),則u線上性序列中出現在v之前。

 

上述介紹抽象,不如用實際案例來解釋一下。假如在VS中建立一個MVC的解決方案XMedia,該方案套件含的項目,以及項目之間的參考關聯性如下表所示:   

項目

引用

XMedia

XMedia.Controllers、XMedia.Models、XMedia.Logics、XMedia.Commons

XMedia.Controllers

XMedia.Models、XMedia.Logics、XMedia.Commons

XMedia.Models

 

XMedia.Logics

XMedia.Models、XMedia.Commons

XMedia.Commons

 

 

 

 

 

 

 

 

 

 

 

項目之間的參考關聯性,是一種依賴關係。如果項目A引用項目B,則表示A依賴B。所以,必須先編譯項目B,再編譯項目A。

根據經驗,我們可以得出上述項目的編譯順序依次是:XMedia.Commons、XMedia.Models、XMedia.Logics、XMedia.Controllers、XMedia。當然,也可以把前兩項對調一下。

項目和參考關聯性構成了一張有向圖圖,項目相當於有向圖中的頂點(Vertex),參考關聯性相當於有向圖中的邊(Edge),而項目的編譯順序就是一個拓撲序列,產生該序列的演算法稱為拓撲排序演算法。

以下是項目參考關聯性的有向圖展示:

拓撲排序演算法的簡要描述:
(1) 從有向圖中選擇一個出度為0的頂點並且輸出它。
(2) 刪去該頂點,並且刪去該頂點的所有邊。
(3) 重複上述兩步,直到剩餘的圖中沒有出度為0的頂點。

按照上述演算法,運行過程示範如下:

第一步 選擇 XMedia.Commons節點

第二步 選擇XMedia.Models節點

第三步 選擇XMedia.Logics節點

第四步 選擇XMedia.Controllers節點

第五步 選擇XMedia節點

 

接下來我們用C#實現代碼實現這個演算法。

由於拓撲排序是一個應用很多的演算法,所以,我們將實現一個通用的排序演算法。在這個通用的演算法中,我們將頂點之間的關係作為依賴關係。代碼如下:

using System;using System.Collections.Generic;using System.Linq;namespace ConsoleApplication1 {    /// <summary>    /// 拓撲排序類。    /// </summary>    public class TopologicSort {        /// <summary>        /// 拓撲順序。        /// </summary>        /// <typeparam name="TKey">節點的索引值類型。</typeparam>        /// <param name="nodes">一組節點。</param>        /// <returns>拓撲序列。</returns>        /// <exception cref="InvalidOperationException">如果存在雙向引用或循環參考,則拋出該異常。</exception>        public IEnumerable<string> OrderBy(IEnumerable<TopologicNode> nodes) {            if (nodes == null) yield break;            //複製一份,便於操作            List<TopologicNode> list = new List<TopologicNode>();            foreach (var item in nodes) {                TopologicNode node = new TopologicNode() { Key = item.Key };                if (item.Dependences != null)                    node.Dependences = new List<string>(item.Dependences);                list.Add(node);            }            while (list.Count > 0) {                //尋找依賴項為空白的節點                var item = list.FirstOrDefault(c => c.Dependences == null || c.Dependences.Count == 0);                if (item != null) {                    yield return item.Key;                    //移除用過的節點,以及與其相關的依賴關係                    list.Remove(item);                    foreach (var otherNode in list) {                        if (otherNode.Dependences != null)                            otherNode.Dependences.Remove(item.Key);                    }                } else if (list.Count > 0) {                    //如果發現有向環,則拋出異常                    throw new InvalidOperationException("存在雙向引用或循環參考。");                }            }        }    }    /// <summary>    /// 拓撲節點類。    /// </summary>    public class TopologicNode {        /// <summary>        /// 擷取或設定節點的索引值。        /// </summary>        public string Key { get; set; }        /// <summary>        /// 擷取或設定依賴節點的索引值列表。        /// </summary>        public List<string> Dependences { get; set; }    }}

 

 

 測試代碼如下:

using System;using System.Collections.Generic;namespace ConsoleApplication1 {    class Program {        static void Main(string[] args) {            List<TopologicNode> nodes = new List<TopologicNode>()            {                new TopologicNode(){ Key = "XMedia",                     Dependences = new List<string>(){ "XMedia.Controllers", "XMedia.Models", "XMedia.Logics", "XMedia.Commons" } },                new TopologicNode(){ Key = "XMedia.Controllers",                    Dependences = new List<string>(){"XMedia.Models","XMedia.Logics","XMedia.Commons"}},                new TopologicNode(){ Key = "XMedia.Logics",                     Dependences = new List<string>(){ "XMedia.Models","XMedia.Commons"}},                new TopologicNode(){ Key = "XMedia.Models" },                new TopologicNode(){ Key = "XMedia.Commons" }            };            //輸出拓撲排序的結果            TopologicSort sort = new TopologicSort();            foreach (var key in sort.OrderBy(nodes)) {                Console.WriteLine(key);            }            Console.ReadLine();        }    }}

運行結果如所示:

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.