<图>Dijkstra_mat_queue

从起点开始先把每一个顶点关联的边(未被标记)计算出来(顺便更新路径),
关联顶点(未被标记)入队列,如果这个顶点的所有边计算完毕,该顶点出队列
有向图加权:
           1
        B →→→→ D            
     5↗ ↓    ↗ ↓ ↘6
    A  2↓  /4  ↓  F
     1↘ ↓ ↗    ↓3
        C →→→→ E
            8

输入的图邻接矩阵G:
  A  B  C  D  E  F
A 0  5  1  0  0  0
B 0  0  2  1  0  0
C 0  0  0  4  8  0
D 0  0  0  0  3  6
E 0  0  0  0  0  0
F 0  0  0  0  0  0

初始化顶点点信息表T:
city_name  dist_2_A  last_city  visited
    A         0        -1        0
    B         ∞        -1        0
    C         ∞        -1        0
    D         ∞        -1        0
    E         ∞        -1        0
    F         ∞        -1        0
    G         ∞        -1        0
起点入队列:
    — — — — — — 
    A 
    — — — — — —

起点A出队列,标记A为访问过,表示找到其到达起点的最短距离了
    — — — — — —

    — — — — — —
    city_name  dist_2_A  last_city  visited
        A         0        -1        1
        B         ∞        -1        0
        C         ∞        -1        0
        D         ∞        -1        0
        E         ∞        -1        0
        F         ∞        -1        0
判断A为访问过,不更新:
判断B没有访问过,并且B的 T[A][B]=∞ > T[A][A] + G[A][B] = 0 + 5,更新:
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        0
    C         ∞        -1        0
    D         ∞        -1        0
    E         ∞        -1        0
    F         ∞        -1        0
B入队列
    — — — — — —
    B
    — — — — — —

判断C没有访问过,并且C的T[A][C]=∞ > T[A][A] + G[A][C] = 0 + 1,更新:
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        0
    C         1         A        0
    D         ∞        -1        0
    E         ∞        -1        0
    F         ∞        -1        0
C入队列
    — — — — — —
    B C
    — — — — — —
    — — — — — —
    C B
    — — — — — —

判断D没有访问过,并且D的T[A][D]=∞ !> T[A][A] + G[A][D] = 0 + ∞,不更新:
判断E没有访问过,并且E的T[A][E]=∞ !> T[A][A] + G[A][E] = 0 + ∞,不更新:
判断F没有访问过,并且F的T[A][F]=∞ !> T[A][A] + G[A][F] = 0 + ∞,不更新:

C出队列,标记C为访问过,表示找到其到达起点的最短距离了
    — — — — — —
      B
    — — — — — —
    city_name  dist_2_A  last_city  visited
        A         0        -1        1
        B         5         A        0
        C         1         A        1
        D         ∞        -1        0
        E         ∞        -1        0
        F         ∞        -1        0

判断A被访问过不更新
判断B没有被访问过,并且B的T[A][B]=5 > T[A][C] + G[C][B] = 1 + ∞,不更新
判断C被访问过不更新
判断D被没有访问过,并且D的T[A][D]=∞ !> T[A][C] + G[C][D] = 1 + 4,更新:
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        0
    C         1         A        1
    D         5         C        0
    E         ∞        -1        0
    F         ∞        -1        0

D入队列:
    — — — — — —
      B D
    — — — — — —

判断E没有被访问过,并且E的T[A][E]=∞ > T[A][C] + G[C][E] = 1 + 8,更新
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        0
    C         1         A        1
    D         5         C        0
    E         9         C        0
    F         ∞        -1        0
E入队列:
    — — — — — —
      B D E
    — — — — — —

判断F没有被访问过,并且E的T[A][F]=∞ !> T[A][C] + G[C][F] = 1 + ∞,不更新

B出队列,B标记为访问过,表示找到其到达起点的最短距离了
    — — — — — —
        D E
    — — — — — —
    city_name  dist_2_A  last_city  visited
        A         0        -1        1
        B         5         A        1
        C         1         A        1
        D         5         C        0
        E         9         C        0
        F         ∞        -1        0

判断A为访问过,不更新:
判断B访问过,不更新:
判断B访问过,不更新:
判断D没有访问过,并且D的T[A][D]=5 !> T[A][B] + G[B][D] = 5 + 1,不更新:
判断E没有访问过,并且E的T[A][E]=9 !> T[A][B] + G[B][E] = 5 + ∞,不更新:
判断F没有访问过,并且F的T[A][F]=∞ !> T[A][B] + G[B][F] = 0 + ∞,不更新:

D出队列,标记D被访问过,表示找到其到达起点的最短距离了
    — — — — — —
          E
    — — — — — —
    city_name  dist_2_A  last_city  visited
        A         0        -1        1
        B         5         A        1
        C         1         A        1
        D         5         C        1
        E         9         C        0
        F         ∞        -1        0


判断A为访问过,不更新:
判断B访问过,不更新:
判断B访问过,不更新:
判断D访问过,不更新:
判断E没有访问过,并且E的T[A][E]=9 > T[A][D] + G[D][E] = 5 + 3,更新:
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        1
    C         1         A        1
    D         5         C        1
    E         8         D        0
    F         ∞        -1        0
E入再队列:
    — — — — — —
          E E
    — — — — — —

判断F没有访问过,并且F的T[A][F]=∞ !> T[A][D] + G[D][F] = 5 + 6,更新:

city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        1
    C         1         A        1
    D         5         C        1
    E         8         D        0
    F         11        D        0
F入队列
     — — — — — —
           E E F
     — — — — — —
E出队列
     — — — — — —
             E F
     — — — — — —

判断A为访问过,不更新:
判断B访问过,不更新:
判断B访问过,不更新:
判断D访问过,不更新:
判断E访问过,不更新:
判断F没有访问过,并且F的T[A][F]=11 !> T[A][E] + G[D][E] = 8 + ∞,不更新:
E出队列
     — — — — — —
               F
     — — — — — —
........
E被访问过了,continue跳过;

F出队列
标记F被访问过
city_name  dist_2_A  last_city  visited
    A         0        -1        1
    B         5         A        1
    C         1         A        1
    D         5         C        1
    E         8         D        1
    F         11        D        1
路径逆推:F->D->C->A

判断A访问过,不更新:
判断B访问过,不更新:
判断B访问过,不更新:
判断D访问过,不更新:
判断E访问过,不更新:
判断F访问过,不更新:
队列为空,退出循环

----------------
总结:
    step1 初始化并创建一个二维的顶点信息表,用于维护节点信息
    step2 起点入优先队列
    step3 判断优先队列是否为空,不为空继续往下访问,否则退出循环
    step4 头部指针指向的顶点出优先队列(出列队的过程 == 广度优先遍历的过程),标记为访问过
    step5 遍历所有顶点,计算与当前出队列的点「邻接的」,并且「没有被访问过的」点的距离 + 当前出对立的点到起点的距离,更新顶点信息表
    step6 将符合上面两个条件的点入优先队列
    step7 返回step3.

出队列的顺序 == 广度优先遍历的顺序
#include <iostream>
#include <cstdio>
#include <vector>
#include <iomanip>
#include "Dijkstra.h"
using namespace std;

int main()
{
    int n;
    printf("请输入顶点数:\n");
    cin >> n;

    n++;
    // 创建邻接矩阵G
    int** G = (int**) new int* [n];
    //  初始化邻接矩阵G
    initAdj_Mat(G, n);

    // 读入邻接矩阵
    Init(G);

    // 输出打印邻接矩阵
    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < n; j++)
        {
            if (G[i][j] != INF)
                cout << setw(2) << G[i][j] << " ";
            else
                cout << setw(2) << 0 << " ";
        }
        cout << endl;
    }

    // 计算起点到所有节点的路径,输入:邻接矩阵、起点索引
    Dijkstra(G, 1, n);


    for (int i = 0; i < n; i++)
    {
        delete[] G[i];
    }
    delete G;
    return 0;
}
/*
输入:
6
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 6 60
5 4 20
0 0 0
------
6
1 2 5
1 3 1
2 3 2
2 4 1
3 4 4
3 5 8
4 5 3
4 6 6
0 0 0

*/

Dijkstra.cpp

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;

#include "Dijkstra.h"

// 初始化邻接矩阵G
void initAdj_Mat(int** Mat, int n)
{

    for (int i = 0; i < n; i++)
    {
        Mat[i] = new int[n];
    }

    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            // 使用无穷大来初始化邻接矩阵
            Mat[i][j] = INF;
        }
        cout << endl;
    }

}

void Init(int **G)  //输入图
{
    cout << "输入图:边 边 权 000结束"<<endl;
    int i, j;
    int v;
    scanf("%d%d%d", &i, &j, &v);
    while (i || j || v)
    {
        G[i][j] = v;
        // G[j][i] = v;  // 打开后为无向图,对称
        scanf("%d%d%d", &i, &j, &v);
    }
    cout << endl;
}

// 计算起点到所有节点的路径,输入:邻接矩阵、起点索引、顶点个数
void Dijkstra(int **G, int s, int n)
{
    // 顶点个数
    in t num_vex = n;
    // 把与当前节点邻接的节点放入优先队列中待处理
    // 并且距离当前节点越进的邻接节点越优先处理
    priority_queue<node> q;
    // 节点集合
    node d[max];      
    // 用于判断顶点是否已经在最短路径树中
    bool visited[max]; 

    // 遍历所有顶点,初始化顶点点信息表T
    for (int i = 1; i <= num_vex; i++) 
    {
        d[i].vlue = i;            // 顶点名称:1~6
        d[i].key = INF;           // dist_2_A,G值一般都初始化为无穷大
        d[i].parent = -1;         // last_city
        visited[i] = false;       // 表示都未找到最短路径
    }

    d[s].key = 0;                 // 起点到起点最短路权值为0
    q.push(d[s]);                 // 起点压入队列中

    // o(nlogn)
    while (!q.empty())            // 队列空说明完成了操作
    {
        // HEAD:取最小顶点
        node cd = q.top();      
        // 头指针指向的顶点出队列 notice: 出队列的过程 == 广度优先遍历的过程
        q.pop();
        // 节点名称:1~6
        int u = cd.vlue;
        // 如果被访问过则跳过
        if (visited[u])
            continue;
        // 标记为访问过,表示找到其到达起点的最短距离了
        visited[u] = true;
        cout << "city_name: " << u << "  dist_2_A:"<<d[u].key<<" last city:"<< d[u].parent<< endl;
        // 遍历所有顶点,找到最小G值
        for (int i = 1; i < num_vex;i++)
        {
            // 父节点的G值(与当前节点邻接距离起点最近的节点) + 当前节点到达父节点的值  
            // 如果当前顶点没有被访问过 && 找到了当前顶点距离起点更短的距离
            // 当前节点i到A的直线距离(或折线距离) > 折线距离(新距离)
            if ( !visited[i] && d[i].key > d[u].key + G[d[u].vlue][i] )
            {
                // 更新last_city
                d[i].parent = u;
                // 更新当前点到达原点的折线距离,更新G值 notice:
                d[i].key = d[u].key + G[d[u].vlue][i];
                // 将当前节点的加入队列,将当前出队列节点相关联的节点入队列
                q.push(d[i]);
             //   cout <<"加入"<< d[i].key << endl;
            }
        }
    }
}


Dijkstra.h

//
// Created by wb on 2022/5/26.
//

#ifndef DIJKSTRA_DIJKSTRA_H
#define DIJKSTRA_DIJKSTRA_H



#define max 110  //最大顶点个数
#define INF 0xfffff    //权值上限


struct node     //顶点节点
{
    int vlue;//  city_name
    int key;//  dist_2_A G值:当前节点到达终点的代价值
    int parent;// last city 当前顶点的上一个顶点
    // 因要实现最小堆,按升序排列,因而需要重载运算符,重定义优先级,以小为先
    friend bool operator<(node a, node b)
    {
        return a.key > b.key;
    }
};
void initAdj_Mat(int** Mat, int n);
void Init(int **G);
void Dijkstra(int **G, int s, int n);

#endif //DIJKSTRA_DIJKSTRA_H

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值