C# 迪傑斯特拉算法 Dijkstra

什麼也不想說,如今直接上封裝的方法:node

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace 算法
{
    /// <summary>
    /// Dijkstra 
    /// 迪傑斯特拉算法
    /// </summary>
    public class Dijkstra : ICloneable
    {

        /// <summary>節點集合</summary>
        public ConcurrentDictionary<String, Node> LN { get; set; }

        /// <summary>開始節點</summary>
        public Node StartNode { get; set; }

        /// <summary>結束節點</summary>
        public Node EndNode { get; set; }

        /// <summary>Dijkstra構造函數</summary>
        /// <param name="list">節點集合</param>
        /// <param name="start">開始節點</param>
        /// <param name="end">結束節點</param>
        public Dijkstra(ConcurrentDictionary<String, Node> list, String start, String end)
        {
            LN = list;
            Init(start, end);
        }

        /// <summary>Dijkstra構造函數</summary>
        /// <param name="list">節點集合</param>
        /// <param name="start">開始節點</param>
        /// <param name="end">結束節點</param>
        public Dijkstra(IEnumerable<Map> list, String start, String end)
        {
            LN = InitNode(list);
            Init(start, end);
        }

        /// <summary>查找最短路徑</summary>
        public bool Find()
        {
            return FindMin(new List<Node> { StartNode }, EndNode);
        }

        /// <summary>初始化</summary>
        private void Init(String start, String end)
        {
            StartNode = LN[start];
            EndNode = LN[end];
            if (StartNode == null || EndNode == null)
            {
                throw new ArgumentNullException();//空異常
            }
            StartNode.SetRank(null);
            StartNode.IsFind = true;

            InitRank(new List<Node> { StartNode });
        }

        /// <summary>初始化點陣的Rank </summary>
        /// <param name="srcs">節點集合</param>
        private void InitRank(IEnumerable<Node> srcs)
        {
            var nextNode = new List<Node>();
            foreach (var node in srcs)
            {
                foreach (var edge in node.LE)
                {
                    edge.CurrentNode.SetRank(node);
                    if (edge.CurrentNode.Rank == (node.Rank + 1) && !nextNode.Contains(edge.CurrentNode))
                        nextNode.Add(edge.CurrentNode);
                }
            }
            if (nextNode.Count > 0) InitRank(nextNode);
        }

        /// <summary>查找</summary>
        /// <param name="srcs">開始結點集合</param>
        /// <param name="dest">結束節點</param>
        private bool FindMin(List<Node> srcs, Node dest)
        {
            dest.GetRank();
            var minLen = 0;
            var isFind = false;
            var nextNodes = new List<Node>();
            string tmpPath;
            foreach (var node in srcs)
            {
                if (node.Equals(dest)) return false;
                foreach (var edge in node.LE)
                {
                    var tempDestRank = edge.CurrentNode.Rank;
                    if (tempDestRank != (node.Rank + 1)) continue;

                    if (!nextNodes.Contains(edge.CurrentNode))
                    {
                        nextNodes.Add(edge.CurrentNode);
                    }
                    edge.CurrentNode.MinDistance = node.MinDistance + edge.Weight;
                    if (!edge.CurrentNode.Equals(dest)) continue;

                    minLen = node.MinDistance + edge.Weight;
                    isFind = true;
                    break;
                }
            }

            if (isFind)
            {
                foreach (var node in srcs)
                {
                    tmpPath = FindMinx(node, dest, node.MinDistance, node.Rank, "", ref minLen);
                    if (tmpPath == "") continue;
                    dest.Path = node.Path + tmpPath;
                    dest.MinDistance = minLen;
                }
            }
            else
            {
                foreach (var next in nextNodes)
                {
                    minLen = -1;
                    foreach (var node in srcs)
                    {
                        if (minLen == -1) minLen = next.MinDistance;
                        tmpPath = FindMinx(node, next, node.MinDistance, node.Rank, "", ref minLen);
                        if (tmpPath == "") continue;
                        next.Path = node.Path + tmpPath;
                        next.MinDistance = minLen;
                    }
                }
                if (nextNodes.Count == 0) return false;
                FindMin(nextNodes, dest);
            }

            return isFind;
        }

        /// <summary>
        /// 尋找起始節點到目標節點的最小路徑,此處採用遞歸查找。目標節點固定,起始節點遞歸。
        /// </summary>
        /// <param name="src">起始節點,爲臨時遞歸節點</param>
        /// <param name="dest">查找路徑中的目標節點</param>
        /// <param name="minx">當前查找最小路徑值,此值在遞歸中共享</param>
        /// <param name="startDist">當前節點以src節點的距離</param>
        /// <param name="srcRank">源節點src的級別</param>
        /// <param name="path">查找中通過的路徑</param>
        private string FindMinx(Node src, Node dest, int startDist, int srcRank, string path, ref int minx)
        {
            var goalPath = "";
            var tmpPath1 = "," + path + ",";
            var tmpPath2 = "," + src.Path + ",";
            foreach (var node in src.LE)
            {
                string tmpPath = path;
                node.CurrentNode.SetRank(src);
                var tmpRank = node.CurrentNode.Rank;
                var tmpNodeName = "," + node.CurrentNode.Name + ",";
                //擴散級別大於等於目標級別而且是未走過的節點。
                if (tmpRank <= srcRank || tmpPath1.IndexOf(tmpNodeName, StringComparison.Ordinal) != -1 ||
                    tmpPath2.IndexOf(tmpNodeName, StringComparison.Ordinal) != -1) continue;
                var tmpLength = node.Weight + startDist;
                if (node.CurrentNode.Equals(dest))
                {
                    if (minx > tmpLength)
                    {
                        minx = tmpLength;
                        tmpPath += "," + node.CurrentNode.Name;
                        goalPath = tmpPath;
                    }
                    else if (minx == tmpLength)
                    {
                        tmpPath += "," + node.CurrentNode.Name;
                        goalPath = tmpPath;
                    }
                }
                else
                {
                    if (tmpLength >= minx) continue;
                    //路程小於最小值,查詢下個子節點
                    tmpPath += "," + node.CurrentNode.Name;
                    tmpPath = FindMinx(node.CurrentNode, dest, tmpLength, srcRank, tmpPath, ref minx);
                    if (tmpPath != "")
                        goalPath = tmpPath;
                }
            }
            return goalPath;
        }

        /// <summary>初始化圖</summary>
        /// <param name="list">圖點集合</param>
        private ConcurrentDictionary<String, Node> InitNode(IEnumerable<Map> list)
        {
            var node = new ConcurrentDictionary<String, Node>();

            foreach (var item in list)
            {
                Node n1;
                Node n2;
                if (!node.ContainsKey(item.N1))
                {
                    n1 = new Node(item.N1);
                    node.TryAdd(item.N1, n1);
                }
                else
                {
                    n1 = node[item.N1];
                }
                if (!node.ContainsKey(item.N2))
                {
                    n2 = new Node(item.N2);
                    node.TryAdd(item.N2, n2);
                }
                else
                {
                    n2 = node[item.N2];
                }
                n1.LE.Add(new Edge(item.N2, item.Weight, n2));
            }
            return node;
        }

        #region 拷貝
        public object Clone()
        {
            return MemberwiseClone();
        }

        /// <summary>淺拷貝</summary>
        public Dijkstra CloneEntity()
        {
            return Clone() as Dijkstra;
        }
        #endregion
    }

    /// <summary>
    /// 節點
    /// </summary>
    public class Node : ICloneable
    {
        /// <summary>節點名稱</summary>
        public String Name { get; set; }

        /// <summary>節點邊集合</summary>
        public List<Edge> LE { get; set; }

        /// <summary>節點級別</summary>
        public Int32 Rank { get; set; }

        /// <summary>最短距離</summary>
        public Int32 MinDistance { get; set; }

        /// <summary>路徑</summary>
        public String Path { get; set; }

        /// <summary>查詢標識</summary>
        public bool IsFind { get; set; }

        public Node(String name)
        {
            Name = name;
            IsFind = false;
            Rank = -1;
            MinDistance = 0;
            LE = new List<Edge>();
        }

        /// <summary>設置節點級別</summary>
        /// <param name="parentNode">父節點</param>
        public void SetRank(Node parentNode)
        {
            if (Rank != -1) return;

            Rank = parentNode != null ? parentNode.Rank + 1 : 0;
        }

        /// <summary>獲取節點級別</summary>
        public Int32 GetRank()
        {
            return Rank;
        }

        #region 拷貝
        public object Clone()
        {
            return MemberwiseClone();
        }

        /// <summary>淺拷貝</summary>
        public Node CloneEntity()
        {
            return Clone() as Node;
        }
        #endregion
    }

    /// <summary>
    /// 節點邊
    /// </summary>
    public class Edge : ICloneable
    {
        /// <summary>邊名稱</summary>
        public String Name { get; set; }

        /// <summary>權值,代價 ,距離</summary>
        public Int32 Weight { get; set; }

        /// <summary>當前向量終點節點</summary>
        public Node CurrentNode { get; set; }

        public Edge(String name, Int32 weight, Node node)
        {
            Name = name;
            Weight = weight;
            CurrentNode = node;
        }

        /// <summary>設置當前節點</summary>
        /// <param name="node">當前向量終點節點</param>
        public void SetCurrentNode(Node node)
        {
            CurrentNode = node;
        }

        #region 拷貝
        public object Clone()
        {
            return MemberwiseClone();
        }

        /// <summary>淺拷貝</summary>
        public Edge CloneEntity()
        {
            return Clone() as Edge;
        }
        #endregion

    }

    /// <summary>圖型</summary>
    public class Map : ICloneable
    {
        /// <summary>節點1</summary>
        public string N1 { get; set; }

        /// <summary>節點2</summary>
        public string N2 { get; set; }

        /// <summary>權值,代價 ,距離</summary>
        public int Weight { get; set; }

        public Map()
        {
        }

        public Map(string n1, string n2, int weight)
        {
            N1 = n1;
            N2 = n2;
            Weight = weight;
        }

        #region 拷貝
        public object Clone()
        {
            return MemberwiseClone();
        }

        /// <summary>淺拷貝</summary>
        public Map CloneEntity()
        {
            return Clone() as Map;
        }
        #endregion

    }

}

 用法:算法

private IEnumerable<Map> InitMap()
        {
            var list = new List<Map>
            {
                new Map("A", "B", 3),
                new Map("A", "C", 5),
                new Map("A", "D", 2),
                new Map("B", "A", 3),
                new Map("B", "C", 4),
                new Map("B", "E", 10),
                new Map("C", "A", 5),
                new Map("C", "B", 4),
                new Map("C", "D", 2),
                new Map("C", "F", 1),
                new Map("C", "G", 6),
                new Map("D", "A", 2),
                new Map("D", "C", 2),
                new Map("D", "H", 3),
                new Map("E", "B", 10),
                new Map("E", "F", 4),
                new Map("E", "I", 2),
                new Map("F", "C", 1),
                new Map("F", "E", 4),
                new Map("F", "K", 8),
                new Map("F", "L", 2),
                new Map("G", "C", 6),
                new Map("G", "H", 8),
                new Map("G", "L", 2),
                new Map("H", "D", 3),
                new Map("H", "G", 8),
                new Map("I", "E", 2),
                new Map("I", "K", 6),
                new Map("I", "J", 1),
                new Map("J", "I", 1),
                new Map("J", "K", 9),
                new Map("K", "J", 9),
                new Map("K", "I", 6),
                new Map("K", "F", 8),
                new Map("K", "L", 5),
                new Map("L", "K", 5),
                new Map("L", "F", 2),
                new Map("L", "G", 2)
            };
            return list;
        }

void 調用(){

var dij = new Dijkstra(InitMap(), start, end);
dij.Find();
var _path = string.Format("最短距離:{0} 路徑:{1}{2}  總耗時:{3} 毫秒 \r\n", dij.EndNode.MinDistance, start,  dij.EndNode.Path, sw.ElapsedMilliseconds); //在界面顯示結果
            
}

 友情鏈接函數

相關文章
相關標籤/搜索