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];
}