图论经典算法——Dijkstra算法

1. 解决问题

目的是求某一顶点到其余各个顶点【最短路径】

2. Dijkstra算法思想

假设一共有两个顶点集合 ST ,集合 S 中存放图中已找到最短路径的顶点,集合 T 中存放图中的剩余顶点。

初始状态时,S 中只包含源点 V0,然后不断通过从集合 T 中选取到顶点 V0 路径长度最短的顶点 Vu 并入集合 S 中。

集合 S 每并入一个新的顶点Vu ,都要修改顶点 V0 到集合 T 中顶点的最短路径长度值。

不断重复这个过程,直到所有顶点全部并入集合 S 中为止。

3. 辅助数据结构

Set T[ ]:已找到最短路径的结点集合。这里为了简单起见用 int T[ ] 表示,当 T[i]==1 表示存在上述集合 S 中,T[i]==0 表示存在上述集合 T 中。

int pre[ ]:记录V0Vi 的前驱结点 Vi-1

int dist[ ]:记录V0Vi 的最短路径的长度。

4. 图的表示

这里采用简单的邻接矩阵表示有向图。

int graph[7][7] = {
        {0, 4, 6, 6, 0, 0, 0},
        {0, 0, 1, 0, 7, 0, 0},
        {0, 0, 0, 0, 6, 4, 0},
        {0, 0, 2, 0, 0, 5, 0},
        {0, 0, 0, 0, 0, 0, 6},
        {0, 0, 0, 0, 1, 0, 8},
        {0, 0, 0, 0, 0, 0, 0}
};

5. 代码描述

5.1 judge()

判断T中是否包含所有的顶点,如果是Set类型则不需要此函数,只需要 set.find(i) 即可。

bool judge(int n) {
    for (int i = 0; i < n; ++i) {
        if (T[i] == 0)
            return false;
    }
    return true;
}

5.2 minIndex()

返回 dist[ ] 数组中所有路径距离最小的顶点下标。

int minIndex(int n) {
    int index = -1;
    int min = INT_MAX;
    for (int i = 0; i < n; i++) {
        if (T[i] == 0 && dist[i] < min) {
            min = dist[i];
            index = i;
        }
    }
    return index;
}

5.3 shortestPath()

第一步:直接可达的顶点,用距离来初始化dist,dist[start]=0,可直达的把距离记录下来作为待定值。

第二步:从待定的距离表中找到最小值min以及对应的顶点 M ,这个值可以作为确定值,为什么?(因为不可能会有图中任何一个顶点 x ,由 start 经过 x 再到顶点 M 产生的距离,要比直接从 start 到 M 更小)

第三步:看这个新确定的顶点的出度,看看从源点出发是经过这个顶点到其邻居近还是直达更近,如果更近就要更新。

void shortestPath(int start, int n) {
    pre[start] = start;
    dist[start] = 0;
    T[start] = 1;
    
	//step1
    for (int i = 0; i < n; i++) {
        if (i != start) {   
            if (graph[start][i] == 0)
                dist[i] = INT_MAX;
            else if (graph[start][i] > 0) {
                dist[i] = graph[start][i];
                pre[i] = start;
            }
        }
    }

    while (judge(n) == false) { 
    	//step2
        int index = minIndex(n);
        T[index] = 1;
        if (judge(n) == true)
            break;

        //step3
        for (int neighbor = 0; neighbor < n; neighbor++) {
            int weight = graph[index][neighbor];
            if (weight > 0 && (dist[index] + weight) < dist[neighbor]) {
                dist[neighbor] = dist[index] + weight;
                pre[neighbor] = index;
            }
        }
    }
}

5.4 main()

应该倒着输出 pre[ ] ,因为存的是前驱结点,也可以用栈处理一下。

int main() {
    int n = sizeof(graph[0]) / sizeof(int);
    shortestPath(0, n);
    for (int i = 0; i < n; ++i) {
        cout << dist[i] << " ";
    }
    cout << endl;
    for (int i = 0; i < n; ++i) {
        cout << pre[i] << " ";
    }
}

6.总结

Dijkstra算法是图论中经典的求最短路径的算法,笔者在学习过程中发现它运用的是动态规划的思想,此外图论还有拓扑排序,Prim、Kruskal求最小生成树算法、求任意两点间的最短路径的Floyd算法,以及求关键路径的算法,这些对于考研和工作来说都是必须掌握的数据结构算法的基本知识,希望与大家共勉!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值