程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#實現路徑規劃(最短路徑)算法

C#實現路徑規劃(最短路徑)算法

編輯:關於C#

以前空閒的時候用C#實現的路徑規劃算法,今日貼它出來,看大家有沒有更 好的實現方案。關於路徑規劃(最短路徑)算法的背景知識,大家可以參考 《C++算法--圖算法》一書。

該圖算法描述的是這樣的場景:圖由節點 和帶有方向的邊構成,每條邊都有相應的權值,路徑規劃(最短路徑)算法就是 要找出從節點A到節點B的累積權值最小的路徑。

首先,我們可以將 “有向邊”抽象為Edge類:

Code

[copy to clipboard]

CODE:

public class Edge
  {
    public string StartNodeID ;
    public string EndNodeID ;
    public double Weight   ; //權值,代價     
  }

節點則抽象成Node類,一個節點上掛著以此節 點作為起點的“出邊”表。

Code

[copy to clipboard]

CODE:

public class Node
  {
    private string iD ;
    private ArrayList edgeList ;//Edge的集合--出邊表
    public Node(string id )
   {
      this.iD = id ;
      this.edgeList = new ArrayList() ;
    }
    property#region property
    public string ID
  {
      get
      {
        return this.iD ;
      }
     }
    public ArrayList EdgeList
   {
       get
     {
        return this.edgeList ;
      }
    }
    #endregion
   }

在計算的過程中,我們需要記錄到達每一個節點權值最小的 路徑,這個抽象可以用PassedPath類來表示:

Code

[copy to clipboard]

CODE:

/// <summary>
  /// PassedPath 用於緩存計算過程中的到達某個節點的權值最小的路徑
   /// </summary>
  public class PassedPath
  {
    private string  curNodeID ;
    private bool   beProcessed ; //是否已被處理
    private double  weight ;     //累積的權值
    private ArrayList passedIDList ; // 路徑
    public PassedPath(string ID)
    {
       this.curNodeID = ID ;
      this.weight  = double.MaxValue ;
      this.passedIDList = new ArrayList() ;
      this.beProcessed = false ;
    }
     #region property
    public bool BeProcessed
     {
      get
      {
         return this.beProcessed ;
      }
      set
      {
        this.beProcessed = value ;
      }
    }
    public string CurNodeID
    {
      get
      {
         return this.curNodeID ;
      }
    }
     public double Weight
    {
      get
       {
        return this.weight ;
       }
      set
      {
         this.weight = value ;
      }
    }
     public ArrayList PassedIDList
    {
      get
      {
        return this.passedIDList ;
      }
    }
    #endregion
  }

另外,還需要一個表PlanCourse來記錄規劃的中間結果,即它管 理了每一個節點的PassedPath。

Code

[copy to clipboard]

CODE:

/// <summary>
  /// PlanCourse 緩存從源節點到其它任一節點的最小權值路徑=》路徑表
  /// </summary>
  public class PlanCourse
  {
     private Hashtable htPassedPath ;  
    #region ctor
    public PlanCourse(ArrayList nodeList ,string originID)
    {
      this.htPassedPath = new Hashtable() ;
      Node originNode = null ;
      foreach(Node node in nodeList)
      {
        if(node.ID == originID)
        {
           originNode = node ;
        }
         else
        {
          PassedPath pPath = new PassedPath(node.ID) ;
           this.htPassedPath.Add(node.ID ,pPath) ;
        }
       }
      if(originNode == null)
       {
        throw new Exception("The origin node is not exist !") ;
      }    
       this.InitializeWeight(originNode) ;
    }
     private void InitializeWeight(Node originNode)
    {
       if((originNode.EdgeList == null) || (originNode.EdgeList.Count == 0))
      {
         return ;
      }
      foreach(Edge edge in originNode.EdgeList)
      {
         PassedPath pPath = this[edge.EndNodeID] ;
        if (pPath == null)
        {
           continue ;
        }
         pPath.PassedIDList.Add(originNode.ID) ;
         pPath.Weight = edge.Weight ;
      }
    }
     #endregion
    public PassedPath this[string nodeID]
    {
      get
      {
         return (PassedPath)this.htPassedPath[nodeID] ;
      }
    }
  }

在所有的基礎構建好後,路徑規劃 算法就很容易實施了,該算法主要步驟如下:

(1)用一張表(PlanCourse) 記錄源點到任何其它一節點的最小權值,初始化這張表時,如果源點能直通某節 點,則權值設為對應的邊的權,否則設為double.MaxValue。

(2)選取沒 有被處理並且當前累積權值最小的節點TargetNode,用其邊的可達性來更新到達 其它節點的路徑和權值(如果其它節點 經此節點後權值變小則更新,否則不更 新),然後標記TargetNode為已處理。

(3)重復(2),直至所有的可達節 點都被處理一遍。

(4)從PlanCourse表中獲取目的點的PassedPath,即為 結果。

下面就來看上述步驟的實現,該實現被封裝在RoutePlanner類中 :

Code

[copy to clipboard]

CODE:

/// <summary>
  /// RoutePlanner 提供圖算法中常用的路徑規劃功 能。
  /// 2005.09.06
  /// </summary>
   public class RoutePlanner
  {
    public RoutePlanner ()
    {      
    }
    #region Paln
    //獲取權值最小的路徑
    public RoutePlanResult Paln(ArrayList nodeList ,string originID ,string destID)
    {
      PlanCourse planCourse = new PlanCourse(nodeList ,originID) ;
      Node curNode = this.GetMinWeightRudeNode(planCourse ,nodeList ,originID) ;
       #region 計算過程
      while(curNode != null)
      {
        PassedPath curPath = planCourse [curNode.ID] ;
        foreach(Edge edge in curNode.EdgeList)
        {
           PassedPath targetPath = planCourse[edge.EndNodeID] ;
           double tempWeight = curPath.Weight + edge.Weight ;
           if(tempWeight < targetPath.Weight)
           {
            targetPath.Weight = tempWeight ;
            targetPath.PassedIDList.Clear() ;
            for(int i=0 ;i<curPath.PassedIDList.Count ;i++)
            {
               targetPath.PassedIDList.Add(curPath.PassedIDList.ToString()) ;
             }
             targetPath.PassedIDList.Add(curNode.ID) ;
          }
        }
        //標志為已處理
         planCourse[curNode.ID].BeProcessed = true ;
         //獲取下一個未處理節點
        curNode = this.GetMinWeightRudeNode(planCourse ,nodeList ,originID) ;
       }
      #endregion
      //表示規劃結束
      return this.GetResult(planCourse ,destID) ;         
    }
    #endregion
    #region private method
    #region GetResult
    //從 PlanCourse表中取出目標節點的PassedPath,這個PassedPath即是規劃結果
    private RoutePlanResult GetResult(PlanCourse planCourse ,string destID)
    {
      PassedPath pPath = planCourse[destID] ;      
      if(pPath.Weight == int.MaxValue)
      {
        RoutePlanResult result1 = new RoutePlanResult(null ,int.MaxValue) ;
         return result1 ;
      }
      string[] passedNodeIDs = new string[pPath.PassedIDList.Count] ;
       for(int i=0 ;i<passedNodeIDs.Length ;i++)
      {
        passedNodeIDs = pPath.PassedIDList.ToString() ;
      }
      RoutePlanResult result = new RoutePlanResult(passedNodeIDs ,pPath.Weight) ;
      return result ;      
    }
    #endregion
     #region GetMinWeightRudeNode
    //從PlanCourse取出一個當 前累積權值最小,並且沒有被處理過的節點
    private Node GetMinWeightRudeNode(PlanCourse planCourse ,ArrayList nodeList ,string originID)
    {
      double weight = double.MaxValue ;
      Node destNode = null ;
       foreach(Node node in nodeList)
      {
         if(node.ID == originID)
        {
           continue ;
        }
         PassedPath pPath = planCourse[node.ID] ;
        if (pPath.BeProcessed)
        {
           continue ;
        }
        if(pPath.Weight < weight)
        {
          weight = pPath.Weight ;
          destNode = node ;
         }
      }
      return destNode ;
    }
    #endregion
    #endregion
   }

2006.05.22 應眾多朋友要求,下面給出一個簡單示例:

RoutePlanner.Plan 過程詳解:

(1)用一張表(PlanCourse)記錄 源點到任何其它一節點的最小權值,初始化這張表時,如果源點能直通某節點, 則權值設為對應的

邊的權,否則設為double.MaxValue

(2)選取沒 有被處理並且當前累積權值最小的節點TargetNode,用其邊的可達性來更新到達 其它節點的路徑和權值(如果其它節點

經此節點後權值變小則更新,否 則不更新),然後標記TargetNode為已處理

(3)重復(2),直至所有的可 達節點都被處理一遍。

(4)從PlanCourse表中獲取目的點的PassedPath, 即為結果。

Code

[copy to clipboard]

CODE:

[STAThread]
    static void Main (string[] args)
    {
      ArrayList nodeList = new ArrayList() ;
      //***************** B Node *******************
      Node aNode = new Node ("A") ;
      nodeList.Add(aNode) ;
       //A -> B
      Edge aEdge1 = new Edge() ;
       aEdge1.StartNodeID = aNode.ID ;
       aEdge1.EndNodeID = "B" ;
      aEdge1.Weight    = 10 ;
      aNode.EdgeList.Add(aEdge1) ;
       //A -> C
      Edge aEdge2 = new Edge() ;
       aEdge2.StartNodeID = aNode.ID ;
       aEdge2.EndNodeID = "C" ;
      aEdge2.Weight    = 20 ;
      aNode.EdgeList.Add(aEdge2) ;
       //A -> E
      Edge aEdge3 = new Edge() ;
       aEdge3.StartNodeID = aNode.ID ;
       aEdge3.EndNodeID = "E" ;
      aEdge3.Weight    = 30 ;
      aNode.EdgeList.Add(aEdge3) ;
       //***************** B Node *******************
      Node bNode = new Node("B") ;
      nodeList.Add (bNode) ;
      //B -> C
      Edge bEdge1 = new Edge() ;
      bEdge1.StartNodeID = bNode.ID ;
       bEdge1.EndNodeID = "C" ;
       bEdge1.Weight   = 5 ;
      bNode.EdgeList.Add(bEdge1) ;
      //B -> E
      Edge bEdge2 = new Edge() ;
      bEdge2.StartNodeID = bNode.ID ;
       bEdge2.EndNodeID = "E" ;
       bEdge2.Weight   = 10 ;
      bNode.EdgeList.Add(bEdge2) ;
      //***************** C Node *******************
      Node cNode = new Node("C") ;
       nodeList.Add(cNode) ;
      //C -> D
       Edge cEdge1    = new Edge() ;
      cEdge1.StartNodeID = cNode.ID ;
      cEdge1.EndNodeID = "D" ;
      cEdge1.Weight   = 30 ;
       cNode.EdgeList.Add(cEdge1) ;
      //***************** D Node *******************
      Node dNode = new Node ("D") ;
      nodeList.Add(dNode) ;
       //***************** C Node *******************
       Node eNode = new Node("E") ;
      nodeList.Add (eNode) ;
      //C -> D
      Edge eEdge1     = new Edge() ;
      eEdge1.StartNodeID = eNode.ID ;
      eEdge1.EndNodeID = "D" ;
       eEdge1.Weight   = 20 ;
      eNode.EdgeList.Add (eEdge1) ;
      RoutePlanner planner = new RoutePlanner() ;
      RoutePlanResult result = planner.Paln(nodeList ,"A" ,"D") ;
      planner = null ;
    }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved