在有向图中找两个点之间最短路径的方法总结
2018-03-21 20:03
381 查看
实验原题如下:
这篇博客中主要讨论在上述情况如何找两点之间的最短路径。
由于上个学期刚接触过类似的问题,所以我首先想到的就是单源求最短路径。Void Dijkstra(GRAPH G, costtype D[MAXVEX+1] )
{ int S[MAXVEX+1] ;
for ( i=1 ; i<=n; i++ )
{ D[i]=G[1][i] ; S[i]=FALSE ; }
S [1]= TRUE ;
for( i=1; i<n; i++)
{ w=mincost ( D, S ) ;
S[w]=TRUE ;
for ( v=2 ; v<= n ; n++ )
if ( S[v]!=TRUE )
{ sum=D[w] + G[w][v] ;
if (sum < D[v] ) D[v] = sum ; }
}
}
int mincost ( D, S )
{
temp = INFINITY ;
w = 2 ;
for ( i=2 ; i<=n ; i++ )
if ( !S[i] && D[i]<temp)
{ temp = D[i] ;
w = i ;
}
return w ;
}算法Dijkstra的原理如下:
它的输入G是一个表示两点之间距离的二维数组,如果两点并非直接相连,则距离为无穷大。
另一个输入D是用于存放该点到其他点之间的最短距离。
当时的想法是尽快达到预期结果,所以使用了更简单的Floyd算法,求任意两点间的最短路径。
输入C是表示两点之间距离的二维数组,输入A用于存放任意两点间的最短路径。
这里需要注意的一点是Floyd算法输入的C,自己到自己的距离应为0,而Dijkstra算法不需要考虑自己到自己的情况。Void Floyd( A , C , n )
{ for ( i = 1; i <= n; i++ )
for ( j = 1; j<=n; j++ )
A[i][j] = C[i][j] ;
for ( k = 1; k <= n; k++ )
for ( i = 1; i <= n; i++ )
for ( j = 1; j <=n; j++ )
if ( A[i][k] + A[k][j] < A[i][j] )
A[i][j] = A[i][k] + A[k][j] ;
}
Floyd算法只需运行一次就能得到全部结果,但是时间复杂度的代价太大,达到了O(n3)。
后来老师讲,现在时间复杂度为O(n2)都不是很好,大于O(n2)的就更看不下去了。
其实实验手册中也提及到,这里最优的算法应该是树的广度优先遍历,即树的层序遍历。使起始点为根结点,两点之间的最短距离就是另一个点在树中的层数-1。但是想使用广度优先遍历寻找最短路径是有条件的,需要默认两点之间的边要么不存在,要么全都等于相等的值。
树的层序遍历算法抽象的伪代码如下Void Level_list_Btree( BTREE T)
{
QUEUE Q;
MAKENULL(Q);
ENQUEUE(T,Q)
while(!EMPTY(Q))
{ P=FRONT(Q);
DEQUEUE(Q);
visite(P->data);
if(P->lchild) ENQUEUE(P->lchild,Q)
if(P->rchild) ENQUEUE(P->rchild,Q);
}
}
它是队列的一种应用,但是怎么得到要找的点在第几层呢?
将点设计为一个类,其中的一个域存放层数,一旦它生成一个孩子结点,就将孩子节点的层数设为父节点的层数+1。public int getDistance(Person person1,Person person2) {
if(!(people.contains(person1)&&people.contains(person2))) {
System.out.println("addEdge输入不在图中的人,程序结束运行");
System.exit(0);}
Set<Person> person_allinqueue = new HashSet<Person>();
person_allinqueue.add(person1);
Queue<Person> queue = new LinkedList<Person>();
queue.offer(person1);
person1.setinitlevel();
while(queue.peek() != null) {
Person father = queue.poll();
if(father == person2) return father.calllevel();
Person[] children= father.callchildren();
if(children.length != 0) {
for(Person child:children) {
if(!person_allinqueue.contains(child)) {
person_allinqueue.add(child);
child.setlevel(father.calllevel()+1);
if(child == person2) return father.calllevel()+1;
queue.offer(child);
}
}
}
}
return -1; }
这篇博客中主要讨论在上述情况如何找两点之间的最短路径。
由于上个学期刚接触过类似的问题,所以我首先想到的就是单源求最短路径。Void Dijkstra(GRAPH G, costtype D[MAXVEX+1] )
{ int S[MAXVEX+1] ;
for ( i=1 ; i<=n; i++ )
{ D[i]=G[1][i] ; S[i]=FALSE ; }
S [1]= TRUE ;
for( i=1; i<n; i++)
{ w=mincost ( D, S ) ;
S[w]=TRUE ;
for ( v=2 ; v<= n ; n++ )
if ( S[v]!=TRUE )
{ sum=D[w] + G[w][v] ;
if (sum < D[v] ) D[v] = sum ; }
}
}
int mincost ( D, S )
{
temp = INFINITY ;
w = 2 ;
for ( i=2 ; i<=n ; i++ )
if ( !S[i] && D[i]<temp)
{ temp = D[i] ;
w = i ;
}
return w ;
}算法Dijkstra的原理如下:
它的输入G是一个表示两点之间距离的二维数组,如果两点并非直接相连,则距离为无穷大。
另一个输入D是用于存放该点到其他点之间的最短距离。
当时的想法是尽快达到预期结果,所以使用了更简单的Floyd算法,求任意两点间的最短路径。
输入C是表示两点之间距离的二维数组,输入A用于存放任意两点间的最短路径。
这里需要注意的一点是Floyd算法输入的C,自己到自己的距离应为0,而Dijkstra算法不需要考虑自己到自己的情况。Void Floyd( A , C , n )
{ for ( i = 1; i <= n; i++ )
for ( j = 1; j<=n; j++ )
A[i][j] = C[i][j] ;
for ( k = 1; k <= n; k++ )
for ( i = 1; i <= n; i++ )
for ( j = 1; j <=n; j++ )
if ( A[i][k] + A[k][j] < A[i][j] )
A[i][j] = A[i][k] + A[k][j] ;
}
Floyd算法只需运行一次就能得到全部结果,但是时间复杂度的代价太大,达到了O(n3)。
后来老师讲,现在时间复杂度为O(n2)都不是很好,大于O(n2)的就更看不下去了。
其实实验手册中也提及到,这里最优的算法应该是树的广度优先遍历,即树的层序遍历。使起始点为根结点,两点之间的最短距离就是另一个点在树中的层数-1。但是想使用广度优先遍历寻找最短路径是有条件的,需要默认两点之间的边要么不存在,要么全都等于相等的值。
树的层序遍历算法抽象的伪代码如下Void Level_list_Btree( BTREE T)
{
QUEUE Q;
MAKENULL(Q);
ENQUEUE(T,Q)
while(!EMPTY(Q))
{ P=FRONT(Q);
DEQUEUE(Q);
visite(P->data);
if(P->lchild) ENQUEUE(P->lchild,Q)
if(P->rchild) ENQUEUE(P->rchild,Q);
}
}
它是队列的一种应用,但是怎么得到要找的点在第几层呢?
将点设计为一个类,其中的一个域存放层数,一旦它生成一个孩子结点,就将孩子节点的层数设为父节点的层数+1。public int getDistance(Person person1,Person person2) {
if(!(people.contains(person1)&&people.contains(person2))) {
System.out.println("addEdge输入不在图中的人,程序结束运行");
System.exit(0);}
Set<Person> person_allinqueue = new HashSet<Person>();
person_allinqueue.add(person1);
Queue<Person> queue = new LinkedList<Person>();
queue.offer(person1);
person1.setinitlevel();
while(queue.peek() != null) {
Person father = queue.poll();
if(father == person2) return father.calllevel();
Person[] children= father.callchildren();
if(children.length != 0) {
for(Person child:children) {
if(!person_allinqueue.contains(child)) {
person_allinqueue.add(child);
child.setlevel(father.calllevel()+1);
if(child == person2) return father.calllevel()+1;
queue.offer(child);
}
}
}
}
return -1; }
public class Person { private String name; private List<Person> children = new ArrayList<Person>(); ; private int level; public void addchild(Person child) { children.add(child); } public Person(String str) { name = str; } public String callname() { return name; } public Person[] callchildren() { Person[] Children = new Person[children.size()]; for (int i = 0; i < children.size(); i++) { Children[i] = children.get(i); } return Children; } public int calllevel() { return level; } public void setinitlevel(){ level = 0; } public void setlevel(int level){ this.level = level; } }在有向图中使用树的层序遍历还需要注意的是,不能形成自环,为此设了一个存放所有进过队列的点的Set Set<Person> person_allinqueue = new HashSet<Person>();用它来确保新进入队列的点不是重复的。
相关文章推荐
- php 两个文件之间的相对路径的计算方法
- 求任意两个点之间的最短路径
- 两个城市之间寻找最短路径问题(广度优先搜索)
- php 计算两个文件之间的相对路径方法
- php 计算两个文件之间的相对路径方法
- LCA算法求任意两个节点之间的最小公共祖先(最短路径)
- 二叉树系列——二叉树中任意两个节点之间的最短路径
- Python小程序:用广度优先搜索算法查询两个url之间的最短路径
- java中两个变量之间交换方法总结
- 弗洛伊德算法得到图中任意两个顶点之间的最短路径
- Java获得项目绝对路径方法总结
- 6)图[6]各顶点之间的最短路径
- 第十三周项目4每对顶点之间的最短路径
- 获取web项目的绝对路径的方法总结
- 两个面之间的最短距离算法(记录)
- 获取web项目的绝对路径的方法总结
- jsp中获得路径的两个方法和获得url路径的方法
- Activity之间传递数据的方法总结
- 所有顶点对之间的最短路径之Floyd-Warshall算法
- ASP.NET中获取两个日期之间的天数的方法(转)