路径规划(最短路径)算法C#实现

https://www.cnblogs.com/zhuweisky/archive/2005/09/29/246677.html


以前空闲的时候用C#实现的路径规划算法,今日贴它出来,看大家有没有更好的实现方案。关于路径规划(最短路径)算法的背景知识,大家可以参考《C++算法--图算法》一书。

该图算法描述的是这样的场景:图由节点和带有方向的边构成,每条边都有相应的权值,路径规划(最短路径)算法就是要找出从节点A到节点B的累积权值最小的路径。

首先,我们可以将“有向边”抽象为Edge类:

    public classEdge

{

public stringStartNodeID ;

public stringEndNodeID   ;

public double Weight      ; //权值,代价            }

节点则抽象成Node类,一个节点上挂着以此节点作为起点的“出边”表。

public classNode

{

private stringiD ;

private ArrayList edgeList ;//Edge的集合--出边表

public Node(stringid )

{

this.iD =id ;

this.edgeList = newArrayList() ;

}

property

}

在计算的过程中,我们需要记录到达每一个节点权值最小的路径,这个抽象可以用PassedPath类来表示:

    /// ///PassedPath 用于缓存计算过程中的到达某个节点的权值最小的路径

///     public classPassedPath

{

private stringcurNodeID ;

private bool     beProcessed ;   //是否已被处理        private double     weight ;        //累积的权值        private ArrayList passedIDList ; //路径public PassedPath(stringID)

{

this.curNodeID =ID ;

this.weight    = double.MaxValue ;

this.passedIDList = newArrayList() ;

this.beProcessed = false;

}

#region propertypublic boolBeProcessed

{

get

{

return this.beProcessed ;

}

set

{

this.beProcessed =value ;

}

}

public stringCurNodeID

{

get

{

return this.curNodeID ;

}

}

public doubleWeight

{

get

{

return this.weight ;

}

set

{

this.weight =value ;

}

}

publicArrayList PassedIDList

{

get

{

return this.passedIDList ;

}

}

#endregion

}

另外,还需要一个表PlanCourse来记录规划的中间结果,即它管理了每一个节点的PassedPath。

/// ///PlanCourse 缓存从源节点到其它任一节点的最小权值路径=》路径表

///     public classPlanCourse

{

privateHashtable htPassedPath ;

#region ctorpublic PlanCourse(ArrayList nodeList ,stringoriginID)

{

this.htPassedPath = newHashtable() ;

Node originNode

= null;

foreach(Node node innodeList)

{

if(node.ID ==originID)

{

originNode

=node ;

}

else

{

PassedPath pPath

= newPassedPath(node.ID) ;

this.htPassedPath.Add(node.ID ,pPath) ;

}

}

if(originNode == null)

{

throw new Exception("The origin node is not exist !") ;

}

this.InitializeWeight(originNode) ;

}

private voidInitializeWeight(Node originNode)

{

if((originNode.EdgeList == null) ||(originNode.EdgeList.Count == 0))

{

return;

}

foreach(Edge edge inoriginNode.EdgeList)

{

PassedPath pPath

= this[edge.EndNodeID] ;

if(pPath == null)

{

continue;

}

pPath.PassedIDList.Add(originNode.ID) ;

pPath.Weight

=edge.Weight ;

}

}

#endregion

public PassedPath this[stringnodeID]

{

get

{

return (PassedPath)this.htPassedPath[nodeID] ;

}

}

}

在所有的基础构建好后,路径规划算法就很容易实施了,该算法主要步骤如下:

(1)用一张表(PlanCourse)记录源点到任何其它一节点的最小权值,初始化这张表时,如果源点能直通某节点,则权值设为对应的边的权,否则设为double.MaxValue。

(2)选取没有被处理并且当前累积权值最小的节点TargetNode,用其边的可达性来更新到达其它节点的路径和权值(如果其它节点   经此节点后权值变小则更新,否则不更新),然后标记TargetNode为已处理。

(3)重复(2),直至所有的可达节点都被处理一遍。

(4)从PlanCourse表中获取目的点的PassedPath,即为结果。

下面就来看上述步骤的实现,该实现被封装在RoutePlanner类中:

    /// ///RoutePlanner 提供图算法中常用的路径规划功能。

///2005.09.06

///     public classRoutePlanner

{

publicRoutePlanner()

{

}

#region Paln//获取权值最小的路径        public RoutePlanResult Paln(ArrayList nodeList ,string originID ,stringdestID)

{

PlanCourse planCourse

= newPlanCourse(nodeList ,originID) ;

Node curNode

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

#region 计算过程while(curNode != null)

{

PassedPath curPath

=planCourse[curNode.ID] ;

foreach(Edge edge incurNode.EdgeList)

{

PassedPath targetPath

=planCourse[edge.EndNodeID] ;

double tempWeight = curPath.Weight +edge.Weight ;

if(tempWeight 

{

targetPath.Weight

=tempWeight ;

targetPath.PassedIDList.Clear() ;

for(int i=0 ;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 ,stringdestID)

{

PassedPath pPath

=planCourse[destID]  ;

if(pPath.Weight == int.MaxValue)

{

RoutePlanResult result1

= new RoutePlanResult(null ,int.MaxValue) ;

returnresult1 ;

}

string[] passedNodeIDs = new string[pPath.PassedIDList.Count] ;

for(int i=0 ;i

{

passedNodeIDs[i]

=pPath.PassedIDList[i].ToString() ;

}

RoutePlanResult result

= newRoutePlanResult(passedNodeIDs ,pPath.Weight) ;

returnresult ;

}

#endregion

#region GetMinWeightRudeNode//从PlanCourse取出一个当前累积权值最小,并且没有被处理过的节点        private Node GetMinWeightRudeNode(PlanCourse planCourse ,ArrayList nodeList ,stringoriginID)

{

double weight = double.MaxValue ;

Node destNode

= null;

foreach(Node node innodeList)

{

if(node.ID ==originID)

{

continue;

}

PassedPath pPath

=planCourse[node.ID] ;

if(pPath.BeProcessed)

{

continue;

}

if(pPath.Weight 

{

weight

=pPath.Weight ;

destNode

=node ;

}

}

returndestNode ;

}

#endregion#endregion

}

 2006.05.22 应众多朋友要求,下面给出一个简单示例:

RoutePlanner.Plan 过程详解:

(1)用一张表(PlanCourse)记录源点到任何其它一节点的最小权值,初始化这张表时,如果源点能直通某节点,则权值设为对应的

边的权,否则设为double.MaxValue

(2)选取没有被处理并且当前累积权值最小的节点TargetNode,用其边的可达性来更新到达其它节点的路径和权值(如果其它节点

经此节点后权值变小则更新,否则不更新),然后标记TargetNode为已处理

(3)重复(2),直至所有的可达节点都被处理一遍。

(4)从PlanCourse表中获取目的点的PassedPath,即为结果。

[STAThread]

static void Main(string[] args)

{

ArrayList nodeList

= newArrayList() ;

//***************** B Node *******************            Node aNode  = new Node("A") ;

nodeList.Add(aNode) ;

//A -> B            Edge aEdge1 = newEdge() ;

aEdge1.StartNodeID

=aNode.ID ;

aEdge1.EndNodeID

= "B";

aEdge1.Weight

= 10;

aNode.EdgeList.Add(aEdge1) ;

//A -> C            Edge aEdge2 = newEdge() ;

aEdge2.StartNodeID

=aNode.ID ;

aEdge2.EndNodeID

= "C";

aEdge2.Weight

= 20;

aNode.EdgeList.Add(aEdge2) ;

//A -> E            Edge aEdge3 = newEdge() ;

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 = newEdge() ;

bEdge1.StartNodeID

=bNode.ID ;

bEdge1.EndNodeID

= "C";

bEdge1.Weight

= 5;

bNode.EdgeList.Add(bEdge1) ;

//B -> E            Edge bEdge2 = newEdge() ;

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        = newEdge() ;

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        = newEdge() ;

eEdge1.StartNodeID

=eNode.ID ;

eEdge1.EndNodeID

= "D";

eEdge1.Weight

= 20;

eNode.EdgeList.Add(eEdge1) ;

RoutePlanner planner

= newRoutePlanner() ;

RoutePlanResult result

= planner.Paln(nodeList ,"A" ,"D") ;

planner

= null;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容