本文将介绍域间路由中使用Dijkstra算法进行求解最短路径。本文将从算法介绍,算法实现,代码解析三个方面进行展开。完整代码在bitbucket上。
Dijkstra算法简介
Dijkstra算法是由E.W.Dijkstra于1959年提出,又叫迪杰斯特拉算法,它应用了贪心算法模式,是目前公认的最好的求解最短路径的方法。算法解决的是有向图中单个源点到其他顶点的最短路径问题,其主要特点是每次迭代时选择的下一个顶点是标记点之外距离源点最近的顶点。
Dijkstra算法实现
本文的域间路由最短路径算法通过修改Dijkstra算法的路径权重进行实现,其算法时间复杂度为O(n2),具体过程如下:
(1)创建两个空集合openSet和closeSet,将源自治系统编号添加到closeSet,将其他所有的自治系统编号添加到openSet中;
(2)针对每个自治系统创建一个数据结构,包括前一跳自治系统编号,以及达到源自治系统的路径权重(初始值为无穷),源自治系统前一跳为自身,路径权重为0;
(3)针对openSet中的每个自治系统,寻找到达closeSet中最短的链路,并更新openSet中自治系统的权值和前一跳自治系统编号,将更新后的路径权重最小的记作minW,对应的自治系统编号记作minAS;
(4)若minW非无穷,将minAS从openSet中删除,并添加到closeSet中;
(5)若openSet非空且存在openSet到达closeSet的链路,跳到第3步;否则进入第6步;
(6)通过各自治系统的前一跳信息,找到源自治系统到达所有其他自治系统的最优路径,结束。
Dijkstra算法代码实现
数据结构
在介绍具体实现函数之前,我们先对主要的数据结构进行简单介绍:
Link
:相邻节点间的链路信息;
Map<Integer,Map<Integer,Link>>NIB
: <源节点,<目的节点,源目的间Link>>存放网络拓扑信息;
Set<Integer> ASNodeNumList
: 所有节点的集合;
Map<Integer, Integer> perviousNode
:记录节点的前驱节点,用来串成源到目的的完整路径;
ASPath
:记录源到目的的路由路径;
Map<Integer,Map<Integer,ASPath>> RIBFromlocal
:记录源到所有目的的路由路径。
MultiPathInit
主要初始化了各个节点间的原始距离。
核心函数实现
此处主要介绍三个函数,MultiPathInit
,shortestNode
,以及calculatePath
。
完整代码在bitbucket上。
MultiPathInit
: 初始化各节点到达源节点的距离;
shortestNode
:选取open集合中达到close集合距离最近的节点;
calculatePath
:计算所有节点的前驱节点。
/**
* Init the MultiPath data.
* @param ASNumSrc
* @param NIB
* @param ASnodeList
* @param ASNodeNumList
* @author xftony
*/
public void MultiPathInit(Integer ASNumSrc, Map<Integer,Map<Integer,Link>>NIB, Set<Integer> ASNodeNumList){
if(NIB==null){
System.out.printf("!!!!!!!!!!!!!NIB is null!!!!!!!!!");
return ;
}
this.open = new HashSet<Integer>();
this.close = new HashSet<Integer>();
this.WeightMap = new HashMap<Integer, Attribute>(); //ASnodeDestNum, val;
this.perviousNode = new HashMap<Integer, Integer>(); //ASnodeDestNum, previousNodeNum;
for(Integer ASNodeNum : ASNodeNumList){
Attribute tmpAttri = new Attribute();
if(!ASNodeNum.equals(ASNumSrc))
open.add(ASNodeNum);
else
close.add(ASNumSrc);
if(NIB.containsKey(ASNumSrc) && NIB.get(ASNumSrc).containsKey(ASNodeNum)
&& NIB.get(ASNumSrc).get(ASNodeNum).started){
tmpAttri.bandwidth = NIB.get(ASNumSrc).get(ASNodeNum).bandWidth;
tmpAttri.brokenTimes = NIB.get(ASNumSrc).get(ASNodeNum).failed - NIB.get(ASNumSrc).get(ASNodeNum).failedOld;
tmpAttri.latency = 1;
tmpAttri.weight = 1;
WeightMap.put(ASNodeNum, tmpAttri);
perviousNode.put(ASNodeNum, ASNumSrc);
}
else if(ASNumSrc.equals(ASNodeNum)){
tmpAttri.bandwidth = Integer.MAX_VALUE;
tmpAttri.latency = 0;
tmpAttri.weight = 0;
WeightMap.put(ASNodeNum, tmpAttri);
perviousNode.put(ASNodeNum, ASNumSrc);
}
else {
WeightMap.put(ASNodeNum, tmpAttri);
perviousNode.put(ASNodeNum, unKnowASnum);
}
}
}
/**
* get the shorest node(the hole path's Weight is min) from openNodes to ASnumInClose
* @param NIB
* @param ASnumInClose
* @return
* @author xftony
*/
public ASSection shortestNode(Map<Integer,Map<Integer,Link>>NIB){
if(close.isEmpty()||open.isEmpty())
return null;
boolean flag = false;
int NodeNumInClose = 0;
int NodeNumInOpen = 0;
int minValue = Integer.MAX_VALUE;
Attribute tmpAttribute = new Attribute();
int tmpWeight = Integer.MAX_VALUE;
int tmpLatency = 0;
int tmpBandwidth = Integer.MAX_VALUE;
ASSection section = new ASSection();
for(Integer nodeOpen : open){
for(Integer nodeClose :close){
if(NIB.containsKey(nodeClose) && NIB.get(nodeClose).containsKey(nodeOpen)
&& NIB.get(nodeClose).get(nodeOpen).started
&& NIB.get(nodeClose).get(nodeOpen).getBandwidth()> minBandWidth){
tmpBandwidth = WeightMap.get(nodeClose).bandwidth < NIB.get(nodeClose).get(nodeOpen).getBandwidth()?
WeightMap.get(nodeClose).bandwidth : NIB.get(nodeClose).get(nodeOpen).getBandwidth();
if(tmpBandwidth < minBandWidth)
continue;
tmpWeight = pathValue(WeightMap.get(nodeClose).weight, NIB.get(nodeClose).get(nodeOpen).failed - NIB.get(nodeClose).get(nodeOpen).failedOld ); //src to dest
tmpLatency = this.WeightMap.get(nodeClose).latency + 1;
if(minValue > tmpWeight){
minValue = tmpWeight;
tmpAttribute.bandwidth = tmpBandwidth;
tmpAttribute.latency = tmpLatency;
tmpAttribute.weight = tmpWeight;
tmpAttribute.linkID = NIB.get(nodeClose).get(nodeOpen).linkID;
NodeNumInClose = nodeClose;
NodeNumInOpen = nodeOpen;
}
flag = true;
}
}
}
if(!flag || tmpAttribute.bandwidth < minBandWidth) //there is no link between open and close, double check the bandwidth
return null;
section.ASNumSrc = NodeNumInClose;
section.ASNumDest = NodeNumInOpen;
section.attribute = tmpAttribute;
return section;
}
/**
* calculate the shortest Path for the topo, the path is store in perviousNode
* @param ASnumInClose
* @param NIB
* @author xftony
*/
public void calculatePath(Map<Integer,Map<Integer,Link>>NIB){
if(NIB.isEmpty())
return;
ASSection newSection = shortestNode(NIB);
if(newSection != null){
close.add(newSection.ASNumDest);
open.remove(newSection.ASNumDest);
int tmpDealyPre = this.WeightMap.get(newSection.ASNumDest).weight;
int tmpDealyCur = newSection.attribute.weight;
if(tmpDealyPre > tmpDealyCur){
this.WeightMap.put(newSection.ASNumDest, newSection.attribute);
this.perviousNode.put(newSection.ASNumDest, newSection.ASNumSrc);
}
calculatePath(NIB);
}
}
以上~