图——单源最短路径(二)Dijkstra算法

图——单源最短路径(二)Dijkstra算法

Dijkstra算法解决的是带权重的有向图上单源最短路径问题,该算法要求图中任意一条边的权重必须为非负值。

1. Dijkstra算法基本思想

对于一个带权重的有向图G=(V,E),若要求其中的一个结点S到图中其余各结点的最短路径,Dijkstra算法的思想是:维护一组结点集合T,从源点S到集合T中的结点的最短路径都已经被找到。算法反复地从V-T中选择最短路径估计最小的结点U,将其加入集合T中,然后对从节点U出发的边进行松弛

补充
(1)最短路径估计:对于一个结点v,用一个属性v.d来记录从源点S到结点v的最短路径权重的上界,则v.d就是从源点S到v的最短路径估计。在Dijkstra算法中,通常会将源点的最短路径估计初始化为0,而将其他结点的最短路径估计初始化为一个极大值。
(2)松弛:对一条边(u, w)进行松弛,前提是从源点S到结点u的最短路径已经确定,而松弛就是看看是否能对从源点S到结点w的最短路径进行改善。具体来说,就是将从S到u之间的最短路径长度加上从结点u到结点w之间的距离,与当前的从S到w的最短路径估计进行比较,如果前者更小,则将后者更新为前者,且此时要将结点w在从S到w之间的最短路径上的前驱结点更改为u。该过程伪代码如下:

// 对边(u, w)进行松弛
// sw[k]表示从源点S到结点k的最短路径估计
// lastnode[k]表示结点k在从源点S到k之间的最短路径上的前驱结点
//matrix[i][j]表示图中从结点i到结点j的距离

void rexlax(int u, int w) {
	if(sw[w] > sw[u] + matrix[u][w]) {
		sw[w] = sw[u] + matrix[u][w];
		lastnode[w] = u;
	}
}

2. Dijkstra算法具体实现

2.1 数据结构

此处采用邻接矩阵来对带权(权重非负)有向图进行表示:

#define Maximum 1000
typedef int VexType;
typedef int MatrixType;

typedef struct GraphAdjMatrix {
    VexType vertexlist[Maximum];
    MatrixType matrix[Maximum][Maximum];
    int vertexnumber;
    int edgenumber;
};

2.2 代码实现

void dijkstra(GraphAdjMatrix g, int s, int *sw, int *lastnode) {
    int i, j, k, n, m;

    int *tip = (int*)malloc(sizeof(int)*(g.vertexnumber+2));

    for(i=1; i<=g.vertexnumber; i++) {
        sw[i] = g.matrix[s][i];
        lastnode[i] = s;
        tip[i] = 0;
    }
    sw[s] = 0;

    for(i=1; i<=g.vertexnumber; i++) {
        j = Biggest;

        for(k=1; k<=g.vertexnumber; k++) {
            if(tip[k]==0 && sw[k]<j) {
                j = sw[k];
                n = k;
            }
        }

        tip[n] = 1;
        for(k=1; k<=g.vertexnumber; k++) {
            if(tip[k]==0 && sw[k] > sw[n] + g.matrix[n][k]) {
                sw[k] = sw[n] + g.matrix[n][k];
                lastnode[k] = n;
            }
        }
    }

}

2.3 测试

测试的图为:
在这里插入图片描述

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<sstream>
#include<list>
#include<stdlib.h>
#include<queue>
#include<algorithm>
using namespace std;

#define Maximum 1000
#define Biggest 100000000

typedef int VexType;
typedef int MatrixType;

typedef struct GraphAdjMatrix {
    VexType vertexlist[Maximum];
    MatrixType matrix[6][6] = { {0},
                                {0, 0, 10, Biggest, 5, Biggest},
                                {0, Biggest, 0, 1, 2, Biggest},
                                {0, Biggest, Biggest, 0, Biggest, 4},
                                {0, Biggest, 3, 9, 0, 2},
                                {0, 7, Biggest, 6, Biggest, 0} };
    int vertexnumber;
    int edgenumber;
};

void dijkstra(GraphAdjMatrix g, int s, int *sw, int *lastnode) {
    int i, j, k, n, m;

    int *tip = (int*)malloc(sizeof(int)*(g.vertexnumber+2));

    for(i=1; i<=g.vertexnumber; i++) {
        sw[i] = g.matrix[s][i];
        lastnode[i] = s;
        tip[i] = 0;
    }
    sw[s] = 0;

    for(i=1; i<=g.vertexnumber; i++) {
        j = Biggest;

        for(k=1; k<=g.vertexnumber; k++) {
            if(tip[k]==0 && sw[k]<j) {
                j = sw[k];
                n = k;
            }
        }

        tip[n] = 1;
        for(k=1; k<=g.vertexnumber; k++) {
            if(tip[k]==0 && sw[k] > sw[n] + g.matrix[n][k]) {
                sw[k] = sw[n] + g.matrix[n][k];
                lastnode[k] = n;
            }
        }
    }

}



int main() {
   GraphAdjMatrix g;
   g.edgenumber = 10;
   g.vertexnumber = 5;


    int *sw = (int*)malloc(sizeof(int)*(g.vertexnumber + 2));
    int *lastnode = (int*)malloc(sizeof(int)*(g.vertexnumber+2));
    int *temp = (int*)malloc(sizeof(int)*(g.vertexnumber+2));  //存储最短路径
    int source = 1;
    dijkstra(g, source, sw, lastnode);
    int i, j, k, a;
    for(i=1; i<=g.vertexnumber; i++) {
        cout<<i<<":"<<sw[i]<<endl;  //打印最短路径长度

		//找出从源点到结点i的最短路径
        j = 0;
        temp[j++] = i;
        k = lastnode[i];
        while(k != source) {
            temp[j++] = k;
            k = lastnode[k];
        }
        temp[j++] = source;
        for(a=j-2; a>=0; a--) {
            cout<<"<"<<temp[a+1]<<","<<temp[a]<<"> ";  //打印最短路径
        }
        cout<<endl<<endl;

    }

    return 0;
}

运行结果:

1:0
<1,1>

2:8
<1,4> <4,2>

3:9
<1,4> <4,2> <2,3>

4:5
<1,4>

5:7
<1,4> <4,5>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值