1. 程式人生 > >狄克斯特拉 Dijkstra 演算法 C#實現

狄克斯特拉 Dijkstra 演算法 C#實現

今天在看《演算法圖解》,看了加權最小路徑演算法,決定用程式碼實現一下。

首先是畫有向圖,在網上找了一下,有不錯的開源軟體graphviz,該原始碼託管在GitLab上。該軟體是一個圖形視覺化軟體。 畫了一個有向圖如下: 圖片描述

畫圖用的程式碼:

digraph dijkstra{
start->A[label="6"]
start->B[label="2"]
A->end[label="1"]
B->A[label="3"]
B->end[label="5"]
}

我建了一個控制檯應用程式:

class Program
    {

        public static List<Node> NodeList { get; set; }
        public static Dictionary<string,int> CostDictionary { get; set; }
        public static Dictionary<string, string> ParentDictionary { get; set; }
        public static List<string> CheckedNodeName { get; set; }

        public Program()
        {
            NodeList= new List<Node>
            {
                new Node
                {
                    NodeName = "start",
                    RelatedNode = new Dictionary<string, int>()
                    {
                        {"A", 6},
                        {"B", 2}
                    }
                },
                new Node
                {
                    NodeName = "A",
                    RelatedNode = new Dictionary<string, int>()
                    {
                        {"end", 1}
                    }
                },
                new Node
                {
                    NodeName = "B",
                    RelatedNode = new Dictionary<string, int>()
                    {
                        {"A", 3},
                        {"end", 5}
                    }
                },
                new Node
                {
                    NodeName = "end",
                    RelatedNode = new Dictionary<string, int>()
                }
            };
            CostDictionary = new Dictionary<string,int>()
            {
                {"A",6},
                {"B",2},
                {"end",int.MaxValue}
            };

            ParentDictionary = new Dictionary<string, string>()
            {
                {"A","start"},
                {"B","start"},
                {"end",""}
            };

            CheckedNodeName=new List<string>();
           
        }

        static void Main(string[] args)
        {
            var progra=new Program();
            Console.WriteLine($"{"parent",10}|{"node",10}|{"cost",10}");
            foreach ( var item in NodeList.SelectMany(node=>node.RelatedNode,(node,relatenode)=>new {node.NodeName,relatenode}))
            {
                Console.WriteLine($"{item.NodeName,10}|{item.relatenode.Key,10}|{item.relatenode.Value,10}");
            }

            while (CheckedNodeName.Count!=CostDictionary.Count)
            {
                //找到Cost最小的節點
                var currentNode = FindMinCostNode(CostDictionary);
                //取出relatednode,
                if (currentNode != null)
                {
                    //迴圈如果subNode的Cost小於CostDictionary的Cost
                    foreach (var subNode in currentNode.RelatedNode)
                    {
                        if (subNode.Value < CostDictionary[subNode.Key])
                        {
                            //替換
                            CostDictionary[subNode.Key] = subNode.Value+ CostDictionary[currentNode.NodeName];
                            ParentDictionary[subNode.Key] = currentNode.NodeName;
                        }
                    }
                    CheckedNodeName.Add(currentNode.NodeName);
                }
            }

            Console.WriteLine("最短路徑:"+ GetTheMinCostPath());

            Console.WriteLine("最短路徑開銷:"+CostDictionary["end"]);

            Console.ReadKey();
        }

        public static string GetTheMinCostPath()
        {
            bool isStart=false;
            string startKey="end";
            string path= "end=>";
            while (!isStart)
            {
               
                path += ParentDictionary[startKey]+"=>";
                startKey = ParentDictionary[startKey];
                if (!ParentDictionary.ContainsKey(ParentDictionary[startKey]))
                {
                    path += ParentDictionary[startKey];
                    isStart = true;
                }
            }

            return path;
        }

        public static Node FindMinCostNode(Dictionary<string,int> costDictionary)
        {
            var costItems= costDictionary.Where(c => !CheckedNodeName.Contains(c.Key)).ToList();
            if (costItems.Any())
            {
                var minCostItem = costItems.OrderBy(c => c.Value).First().Key;
                return NodeList.FirstOrDefault(n => n.NodeName == minCostItem);
            }
            return null;
        }
    }

    public class Node
    {
        public string NodeName { get; set; }
        public Dictionary<string, int> RelatedNode { get; set; }
    }

    public class CostItem
    {
        public string ParentName { get; set; }
        public string NodeName { get; set; }
        public int Cost { get; set; }
    }