C# 判斷有向圖是否存在環

代碼實現

Program.cs

using System;

namespace Csharp_test
{
    static class Program
    {
        /// <summary>
        /// 應用程序的主入口點。
        /// </summary>
        [STAThread]
        static void Main()
        {
            MyList mylist = new MyList();
            mylist.addNode("a");
            mylist.addNode("b");
            mylist.addNode("c");
            mylist.addNode("d");
            mylist.addNode("e");
            mylist.addEdge("a", new string[] {"b","c"});
            mylist.addEdge("b", new string[] {"c" });
            mylist.addEdge("c", new string[] {"d" });
            mylist.addEdge("d", new string[] {"e" });
            mylist.addEdge("e", new string[] {"a" });
            bool flag = mylist.topologicalSort();
            Console.WriteLine(flag ? "無環" : "有環");
        }
    }
}

MyList.cs

using System.Collections.Generic;

namespace Csharp_test
{
    class MyList
    {
        /// <summary>
        /// 頂點字符串名稱-編號字典
        /// </summary>
        private Dictionary<string, int> noteIntDictionary = new Dictionary<string, int>();
        private Dictionary<int, string> noteStringDictionary = new Dictionary<int, string>();
        private static int[] emptyIntArray = { }; // 空Int數組
        private int cnt = 0;    // 頂點編號

        /// <summary>
        /// 頂點入度數
        /// </summary>
        private List<int> inDegree = new List<int>();

        /// <summary>
        /// 頂點邊集合
        /// 數組下標爲頂點編號,對應內容是頂點的出度連接編號
        /// </summary>        
        private List<int[]> edge = new List<int[]>();

        /// <summary>
        /// 最長路徑
        /// </summary>  
        private List<int> dist = new List<int>();

        /// <summary>
        /// 添加頂點
        /// </summary>
        /// <param name="nodeName">頂點字符串</param>
        /// <returns>
        ///     true: 頂點添加成功
        ///     false: 頂點編號重複
        /// </returns>
        public bool addNode(string nodeName)
        {
            if (noteIntDictionary.ContainsKey(nodeName) == false)
            {
                // 加入節點字典
                noteIntDictionary.Add(nodeName, cnt);
                noteStringDictionary.Add(cnt, nodeName);
                inDegree.Add(0); 
                dist.Add(0);
                edge.Add(emptyIntArray);
                cnt++;
                return true;
            }
            return false;
        }

        /// <summary>
        /// 爲網絡各頂點添加有向邊,將終點轉爲數字編號
        /// </summary>
        /// <param name="nodeName">頂點字符串</param>
        /// <param name="nodeOutDegree">頂點出度數組</param>
        /// <returns></returns>
        public bool addEdge(string nodeName, string[] nodeOutDegree)
        {
            // 判斷字典中是否含有該頂點
            if (noteIntDictionary.ContainsKey(nodeName) == true)
            {
                // 頂點字符串轉爲編號
                int nodeNum = noteIntDictionary[nodeName];
                int tempNum = edge[nodeNum].Length;
                int[] edgeNum = new int[tempNum + nodeOutDegree.Length];
                if (tempNum > 0)
                {
                    edge[nodeNum].CopyTo(edgeNum, 0);
                }
                for (int i = tempNum; i < nodeOutDegree.Length; i++)
                {
                    string nodeOutDegree_temp = nodeOutDegree[i];
                    // 判斷字典中是否含有該節點
                    if (noteIntDictionary.ContainsKey(nodeOutDegree_temp) == false)
                    {
                        return false;
                    }
                    // 頂點添加出度編號
                    int nodeOutDegreeNum_temp = noteIntDictionary[nodeOutDegree_temp];
                    inDegree[nodeOutDegreeNum_temp]++;
                    edgeNum[i] = nodeOutDegreeNum_temp;
                }
                edge[nodeNum] = edgeNum;
                return true;
            }
            return false;
        }


        /// <summary>
        /// 拓撲排序
        /// </summary>
        /// <returns>
        /// true: 無環
        /// false: 有環
        /// </returns>
        public bool topologicalSort() 
        {
            Queue<int> zeroNode = new Queue<int>();
            List<int> inDegree_temp = new List<int>(inDegree);
            for (int i=0; i <cnt;++i)
            {
                if(inDegree_temp[i] == 0)
                {
                    zeroNode.Enqueue(i);
                }
            }
            int count = 0;
            while(zeroNode.Count != 0)
            {
                // TODO: 可能會出現異常
                int index = zeroNode.Dequeue();
                ++count;
                foreach(int nodeNum_temp in edge[index])
                {
                    --inDegree_temp[nodeNum_temp];
                    if(inDegree_temp[nodeNum_temp] == 0)
                    {
                        zeroNode.Enqueue(nodeNum_temp);
                    }
                }
            }
            return count == cnt;
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章