关于图的最短路径问题

1.单源最短路径:(书上源代码加上自己的注释)

//单源最短路径,Dijkstra算法
//从s开始寻找最短路径,将他们记录在数组D中
void Dijkstra ( Graph* G,int* D,int s) {
 int i,v,w;
 for(i=0;i<G->n();i++) {
  v = minVertex(G,D); //找出未被访问且权值最小的顶点
  if(D[v] == INFINITY) return ;  //如果还未设定从s到v的权值,退出循环
  G->setMark(v,VISITED);    //标记为已经遍历过
  for(w=G->first(v);w<G->n();w=G->next(v,w) )  //从v出发,遍历v的每一个相邻结点
   if(D[w]>(D[v]+G->weight(v,w) ) ) //如果存在D[v]+weight(v,w)小于当前权值D[w]
    D[w] = D[v]+G->weight(v,w);  //将最小权值D[w]设为D[v]+weight(v,w)
}
//实现minVertex的第一种方式,时间代价为V平方
int minVertex(Graph* G,int* D) {
int i,v;
for(i=0;i<G->n();i++)
 if(G->getMark(i)==UNVISITED) { v = i;break; }  //先找出第一个未访问的结点
for(i++;i<G->n();i++)                                  //遍历第一个未访问结点后的结点
 if((G->getMark(i)==UNVISITED)&&(D[i]<D[v]))    //如果后续结点为未访问且权值比之前那个小
  v = i;                                 //则将v设为结点
return v;                                              //返回该结点

实现minVertex的第二种方式是将未被处理的顶点按照D值大小的顺序保存在一个最小堆中,每次改变D(x)值时,都可以通过

先删除再重新插入的方法改变顶点x在堆中的位置。由于储存在堆中的对象需要知道它的顶点号和距离值,为此创建一个简单

的类,名为DijkElem:
class DijkElem {
public:
 int vertex,distance;  //记录顶点和距离值(权值)
 DijkElem() { vertex = v;distance = d; }
 DijkElem(int v,int d) { vertex = v;distance = d; }
};

//优先队列实现Dijkstra算法
void Dijkstra(Graph* G,int* D,int s){
 int i,v,w;
 DijkElem temp;
 DijkElem E[G->e()];   //开辟一块heap内存存储DijkElem组成的数组
 temp.distance = 0;temp.vertex = s;  //将temp设置为起始顶点
 E[0] = temp;    //初始化数组的第一个元素为temp
 minheap<DijkElem,DDComp> H(E,1,G->e() ) //生成一个最小堆
 for(i=0;i<G->n();i++){
  do (
   if(!H.removemin(temp)) return;   //如果堆为空,跳出循环
   v = temp.vertex;
  } while(G->getMark(v)==VISITED);  //找出第一个未被访问的结点
  G->setMark(v,VISITED);
  if(D[v] == INFINITY) return;   //如果权值未设定,跳出循环
  for(w=G->first(v);w<G->n();w=G->next(v,w) )
   if(D[w]>(D[v]+G->weight(v,w))) {   //如果找到更小的D[w]
    D[w] = D[v]+G->weight(v,w);  //更新D[w]
    temp.distance = D[w];temp.vertex = w;   //更新temp对象
    H.insert(temp);   //重新插入
   }
  }
}
  

2.查看每对顶点间的最短路径:
//Floyd算法
//定义k-path是任意一条从顶点v到顶点u的中间顶点(除了v和u外)序号都小于k的路径
//定义Dk(v,u)为从v到u长度最小的k-path
//假设已知从v到u的最短k-path,则最短(k+1)-path或者经过顶点k,或者不经过。如果经过k,最短(k+1)-path的一部分是从

//v到k的最短路径,另一部分是从k到u的最短路径k-path.如果不经过k,则保持原值
//是密集图最好的选择,时间代价为V的三次方
void Floyd(Graph* G) {
 int D[G->n()][G->n()];
 for(int i=0;i<G->n();i++)    
  for(int j=0;j<G->n();j++)
   D[i][j] = G->weight(i,j);   //先初始化所有权值
 for(int k=0;k<G->n();k++)
  for(int i=0;i<G->n();i++)
   for(int j=0;j<G->n();j++)
    if(D[i][j]>(D[i][k]+D[k][j]))
     D[i][j] = D[i][k]+D[k][j]; 
}
   

 

 
 

你可能感兴趣的:(算法,存储,Graph,Class,distance)