gaoxiang

专注于.NET技术

博客园 首页 新随笔 联系 订阅 管理
以前空闲的时候用C#实现的路径规划算法,今日贴它出来,看大家有没有更好的实现方案。关于路径规划(最短路径)算法的背景知识,大家可以参考《C++算法--图算法》一书。
    该图算法描述的是这样的场景:图由节点和带有方向的边构成,每条边都有相应的权值,路径规划(最短路径)算法就是要找出从节点A到节点B的累积权值最小的路径。
    首先,我们可以将“有向边”抽象为Edge类:
    public class Edge
    {
        
public string StartNodeID ;
        
public string EndNodeID   ;
        
public double Weight      ; //权值,代价        
    }
    节点则抽象成Node类,一个节点上挂着以此节点作为起点的“出边”表。
       public class Node
    
{
        
private string iD ;
        
private ArrayList edgeList ;//Edge的集合--出边表

        
public Node(string id )
     
{
            
this.iD = id ;
            
this.edgeList = new ArrayList() ;
        }


        
property
    }
    
    在计算的过程中,我们需要记录到达每一个节点权值最小的路径,这个抽象可以用PassedPath类来表示:
    /// <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。

    
/// <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类中:
    /// <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[i].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[i] 
= pPath.PassedIDList[i].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
    }

Feedback

# re: 路径规划(最短路径)算法C#实现  回复   

2005-09-29 19:50 by lovesanni
正需要这样的算法,谢了:)

# re: 路径规划(最短路径)算法C#实现  回复   

2005-10-16 17:17 by www
盒模型bug的解决方法
作者:阿捷 2004-7-22 22:37:07

# java实现  回复   

2006-01-31 10:40 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

/**
* @author 周振興
* @version 1.00
*/
public class Edge {
public String StartNodeID;

public String EndNodeID;

public double Weight;

/**
* @return Returns the endNodeID.
*/
public String getEndNodeID() {
return EndNodeID;
}

/**
* @param endNodeID The endNodeID to set.
*/
public void setEndNodeID(String endNodeID) {
EndNodeID = endNodeID;
}

/**
* @return Returns the startNodeID.
*/
public String getStartNodeID() {
return StartNodeID;
}

/**
* @param startNodeID The startNodeID to set.
*/
public void setStartNodeID(String startNodeID) {
StartNodeID = startNodeID;
}

/**
* @return Returns the weight.
*/
public double getWeight() {
return Weight;
}

/**
* @param weight The weight to set.
*/
public void setWeight(double weight) {
Weight = weight;
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:41 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

import java.util.ArrayList;

/**
* @author 周振興
* @version 1.00
*/
public class Node {
private String iD;

private ArrayList edgeList;

public Node(String id) {
this.iD = id;
this.edgeList = new ArrayList();
}

/**
* @return Returns the edgeList.
*/
public ArrayList getEdgeList() {
return edgeList;
}

/**
* @param edgeList The edgeList to set.
*/
public void setEdgeList(ArrayList edgeList) {
this.edgeList = edgeList;
}

/**
* @return Returns the iD.
*/
public String getID() {
return iD;
}

/**
* @param id The iD to set.
*/
public void setID(String id) {
iD = id;
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:42 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

import java.util.ArrayList;

/**
* @author 周振興
* @version 1.00
*/
public class PassedPath {
private String curNodeID;

private boolean beProcessed;

private double weight;

private ArrayList passedIDList;

public PassedPath(String ID) {
this.curNodeID = ID;
this.weight = Double.MAX_VALUE;
this.passedIDList = new ArrayList();
this.beProcessed = false;
}

/**
* @return Returns the beProcessed.
*/
public boolean isBeProcessed() {
return beProcessed;
}

/**
* @param beProcessed The beProcessed to set.
*/
public void setBeProcessed(boolean beProcessed) {
this.beProcessed = beProcessed;
}

/**
* @return Returns the curNodeID.
*/
public String getCurNodeID() {
return curNodeID;
}

/**
* @param curNodeID The curNodeID to set.
*/
public void setCurNodeID(String curNodeID) {
this.curNodeID = curNodeID;
}

/**
* @return Returns the passedIDList.
*/
public ArrayList getPassedIDList() {
return passedIDList;
}

/**
* @param passedIDList The passedIDList to set.
*/
public void setPassedIDList(ArrayList passedIDList) {
this.passedIDList = passedIDList;
}

/**
* @return Returns the weight.
*/
public double getWeight() {
return weight;
}

/**
* @param weight The weight to set.
*/
public void setWeight(double weight) {
this.weight = weight;
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:42 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

import java.util.ArrayList;
import java.util.Hashtable;

/**
* @author 周振興
* @version 1.00
*/
public class PlanCourse {
private Hashtable htPassedPath;

public PlanCourse(ArrayList nodeList, String originID) throws Exception {
this.htPassedPath = new Hashtable();

Node originNode = null;
for (int i = 0; i < nodeList.size(); i++) {
Node node = (Node) nodeList.get(i);
if (node.getID() == originID) {
originNode = node;
} else {
PassedPath pPath = new PassedPath(node.getID());
this.htPassedPath.put(node.getID(), pPath);
}
}

if (originNode == null) {
throw new Exception("The origin node is not exist !");
}

this.InitializeWeight(originNode);
}

private void InitializeWeight(Node originNode) {
if ((originNode.getEdgeList() == null) || (originNode.getEdgeList().size() == 0)) {
return;
}

for (int i = 0; i < originNode.getEdgeList().size(); i++) {
Edge edge = (Edge) originNode.getEdgeList().get(i);
PassedPath pPath = getPassedPath(edge.EndNodeID);
if (pPath == null) {
continue;
}
pPath.getPassedIDList().add(originNode.getID());
pPath.setWeight(edge.getWeight());
}
}

public PassedPath getPassedPath(String nodeID) {
return (PassedPath) this.htPassedPath.get(nodeID);
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:43 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

import java.util.ArrayList;

/**
* @author 周振興
* @version 1.00
*/
public class RoutePlanner {
public RoutePlanner() {
}

public RoutePlanResult Paln(ArrayList nodeList, String originID, String destID) throws Exception {
PlanCourse planCourse = new PlanCourse(nodeList, originID);

Node curNode = this.GetMinWeightRudeNode(planCourse, nodeList, originID);

while (curNode != null) {
PassedPath curPath = planCourse.getPassedPath(curNode.getID());
for (int j = 0; j < curNode.getEdgeList().size(); j++) {
Edge edge = (Edge) curNode.getEdgeList().get(j);
PassedPath targetPath = planCourse.getPassedPath(edge.EndNodeID);
double tempWeight = curPath.getWeight() + edge.getWeight();

if (tempWeight < targetPath.getWeight()) {
targetPath.setWeight(tempWeight);
targetPath.getPassedIDList().clear();

for (int i = 0; i < curPath.getPassedIDList().size(); i++) {
targetPath.getPassedIDList().add(curPath.getPassedIDList().get(i).toString());
}

targetPath.getPassedIDList().add(curNode.getID());
}
}

planCourse.getPassedPath(curNode.getID()).setBeProcessed(true);
curNode = this.GetMinWeightRudeNode(planCourse, nodeList, originID);
}
return this.GetResult(planCourse, destID);
}

private RoutePlanResult GetResult(PlanCourse planCourse, String destID) {
PassedPath pPath = planCourse.getPassedPath(destID);

if (pPath.getWeight() == Integer.MAX_VALUE) {
RoutePlanResult result1 = new RoutePlanResult(null, Integer.MAX_VALUE);
return result1;
}

String[] passedNodeIDs = new String[pPath.getPassedIDList().size()];
for (int i = 0; i < passedNodeIDs.length; i++) {
passedNodeIDs[i] = pPath.getPassedIDList().get(i).toString();
}
RoutePlanResult result = new RoutePlanResult(passedNodeIDs, pPath.getWeight());

return result;
}

private Node GetMinWeightRudeNode(PlanCourse planCourse, ArrayList nodeList, String originID) {
double weight = Double.MAX_VALUE;
Node destNode = null;

for (int i = 0; i < nodeList.size(); i++) {
Node node = (Node) nodeList.get(i);
if (node.getID() == originID) {
continue;
}

PassedPath pPath = planCourse.getPassedPath(node.getID());
if (pPath.isBeProcessed()) {
continue;
}

if (pPath.getWeight() < weight) {
weight = pPath.getWeight();
destNode = node;
}
}

return destNode;
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:43 by flyfreely
//==========================================================================
// version 変更日 変更者 変更内容
//--------------------------------------------------------------------------
// 1.00 2006/01/31 周振興    新規作成
//**************************************************************************
package path;

/**
* @author 周振興
* @version 1.00
*/
public class RoutePlanResult {
private String[] passedNodeIDs;

private double weight;

public RoutePlanResult(String[] strings, double d) {
this.passedNodeIDs = strings;
this.weight = d;
}

/**
* @return Returns the passedNodeIDs.
*/
public String[] getPassedNodeIDs() {
return passedNodeIDs;
}

/**
* @param passedNodeIDs The passedNodeIDs to set.
*/
public void setPassedNodeIDs(String[] passedNodeIDs) {
this.passedNodeIDs = passedNodeIDs;
}

/**
* @return Returns the weight.
*/
public double getWeight() {
return weight;
}

/**
* @param weight The weight to set.
*/
public void setWeight(double weight) {
this.weight = weight;
}
}

# re: 路径规划(最短路径)算法C#实现  回复   

2006-01-31 10:45 by flyfreely
嫌来无视,把c#代码转换成java代码
呵呵,也不知道对不对,给以后的各位提供一个方便

# re: 路径规划(最短路径)算法C#实现  回复   

2006-02-06 18:13 by gg
有没有初始化 以及取结果的代码

# re: 路径规划(最短路径)算法C#实现  回复   

2006-03-26 14:45 by hazy
为什么没有初始化,和获得查询就结果的代码?
请回复qq:13448739

# 我知道如何初始化了阿  回复   

2006-03-27 18:06 by hazy
我知道如何初始化了阿

# re: 路径规划(最短路径)算法C#实现  回复   

2006-03-27 18:07 by hazy
8过,我觉得用arraylist速度比较慢,建议斑竹修改。我准备修改一下哦

# re: 路径规划(最短路径)算法C#实现  回复   

2006-05-14 01:39 by x00ganlu
收下,谢谢斑竹
posted on 2006-05-18 13:26  S孤单一吻S  阅读(2154)  评论(0编辑  收藏  举报