• C++实现图的遍历和最短路径


    摘自:https://blog.csdn.net/qq_45694646/article/details/106764026

    C++实现图的基本操作

    数据结构之图(存储,遍历,最短路径)
    图是一种比线性表和树更为复杂的数据结构,它是“多对多”的关系。图(Graph)G是由两个集合V和E组成,记为G=(V,E)。

    一、图的邻接矩阵存储
    邻接矩阵法来表示图,需要用一个二维数组来存储邻接矩阵,一个一维数组来存储顶点信息。用邻接矩阵来存储图有它的优点也有它的缺点:
    优点:容易实现图的操作,如:求某顶点的度、判断顶点之间是否有边、找顶点的邻接点等等。
    缺点:n个顶点需要n*n个单元存储边;空间效率为O(n2)。 对稀疏图而言尤其浪费空间。
    代码实现

    #define MaxInt 32767        //表示极大值 即无穷大
    #define MVNum 100            //最大顶点数
    typedef string VerTexType;    //设顶点的数据类型为string,需#include<string>
    typedef int ArcType;        //设权值类型为整型
    
    typedef struct
    {
        VerTexType vexs[MVNum];        //顶点表
        ArcType arcs[MVNum][MVNum];    //邻接矩阵
        int vexnum, arcnum;            //图的当前点数和边数
    }AMGraph;

    二、用邻接矩阵来创建无向网

    【算法思想】:
    1.输入总顶点数和总边数
    2.依次输入点的信息存入顶点表中
    3.初始化邻接矩阵,使每个权值初始化为极大值
    4.构造邻接矩阵

    代码实现

    bool CreateUDN(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j, k ;
        VerTexType v1, v2;
        ArcType w;
        cout << "请输入图的顶点总数和边的总数:";
        cin >> G.vexnum >> G.arcnum;    //输入总顶点数,总边数
        cout << "请依次输入顶点信息:" << endl;
        for (i = 0; i < G.vexnum; ++i)
            cin >> G.vexs[i];            //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
        cout << "请输入边的信息,格式:头,尾,权值" << endl;
        for (k = 0; k < G.arcnum; ++k)
        {
            cin >> v1 >> v2 >> w;        //输入一条边依附的顶点及权值
            i = LocateVex(G, v1);j= LocateVex(G, v2);        //确定v1,v2在G中的位置,即顶点数组的下标
            G.arcs[i][j] = w;        //边<v1,v2>的权值为w
            G.arcs[j][i] = G.arcs[i][j];    //对称边
        }
        return true;
    }

    LocateVex()函数:查询顶点是否在顶点表中,若在则返回顶点表中的下标;否则返回-1

    int LocateVex(AMGraph G, VerTexType u)
    {//存在则返回u在顶点表中的下标;否则返回-1
        int i;
        for (i = 0; i < G.vexnum; ++i)
            if (u == G.vexs[i])
                return i;
        return -1;
    }

    输出无向网的信息

    void PrintGraph(AMGraph G)
    {
        int i, j;
        cout << "图的邻接矩阵存储信息:" << endl;
        cout << "顶点信息:" << endl;
        for (i = 0; i < G.vexnum; i++)
            cout << i << ":" << G.vexs[i] << endl;    //输出顶点信息
        cout << "邻接矩阵数据:" << endl;
        for (i = 0; i < G.vexnum; i++)
        {
            for (j = 0; j < G.vexnum; j++)
            {
                if (G.arcs[i][j] == MaxInt)
                    cout << left<<setw(6)<<"";    
                else
                    cout << left<<setw(6) << G.arcs[i][j];
            }
            cout << endl;
        }
    }

    三、图的遍历
    遍历的定义:从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算
    遍历的实质:找每个顶点的邻接点的过程

    1.深度优先遍历
    简单归纳:
    (1) 访问起始点v;
    (2) 若v的第1个邻接点没访问过,深度遍历此邻接点;
    (3) 若当前邻接点已访问过,再找v的第2个邻接点重新遍历

    辅助数组:
    避免重复访问,bool visited[MVNum];初值为false,若i被访问,则改visited[i]=true;

    代码实现:

    void DFS_AM(AMGraph G, int v)    //深度优先搜索遍历,从第v个顶点开始
    {
        cout <<setw(8)<< G.vexs[v]; visited[v] = true;    //访问第v个顶点,并置visited数组对应的值为true
        for (int w = 0; w < G.vexnum; w++)
            if ((G.arcs[v][w] != 0) && (!visited[w]))
                DFS_AM(G,w);        //G.arcs[v][w] != 0表示w是v的邻接点,如果w未访问,则递归调用DFS_AM
    }

    DFS算法效率分析:
    (1)用邻接矩阵来表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度为O(n2)。
    (2)用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)
    (3)结论:稠密图适于在邻接矩阵上进行深度遍历;稀疏图适于在邻接表上进行深度遍历。

    2.广度优先遍历
    简单归纳:
    (1)在访问了起始点v之后,依次访问 v的邻接点
    (2)然后再依次访问这些顶点中未被访问过的邻接点
    (3)直到所有顶点都被访问过为止

    辅助队列:
    这里用的是链队列,用顺序队列(循环队列)也可以。

    //队列的DAT//
    typedef int Elemtype; //BFS中队列存放的是图元素下标
    typedef int Status;
    typedef struct QNode {
        Elemtype data;
        struct QNode* next;
    }*QueuePrt;
    typedef struct {
        QueuePrt front, rear;    //指针形式的对头和队尾指针
    }*LinkQueue;
    要写出队列的基本操作函数:
    初始化 Status InitQuene(LinkQueue q) ;
    判空操作 bool QueueEmpty(LinkQueue Q) ;
    入队操作 Status EnQueue(LinkQueue q, Elemtype e);
    出队操作Status DeQueue(LinkQueue q, Elemtype* e);
    
    Status InitQuene(LinkQueue q)
    {
        if (NULL == q) {
            return -1;
        }
    
        q->front = NULL;
        q->rear = NULL;
    
        return 0;
    }
    
    bool QueueEmpty(LinkQueue Q)
    {
        if (NULL == Q) {
            return true;
        }
    
    
        if (NULL == Q->front)
        {
            return true;
        }
    
        return false;
    }
    
    Status EnQueue(LinkQueue q, Elemtype e)
    {
        QueuePrt QP = NULL;
    
        if (NULL == q) {
            return -1;
        }
    
        QP = (QueuePrt)calloc(1, sizeof(struct QNode));
    
        QP->data = e;
        QP->next = NULL;
    
        if (NULL == q->front) {
            q->front = QP;
            q->rear = QP;
        } else {
            q->rear->next = QP;
            q->rear = QP;
        }
    
        return 0;
    }
    
    Status DeQueue(LinkQueue q, Elemtype *e)
    {
        QueuePrt QP = NULL;
        QueuePrt QP_prev = NULL;
        QueuePrt front = NULL;
    
        if (NULL == q || NULL == e) {
            return -1;
        }
    
    
        if (QueueEmpty(q)) {
            return 0;
        }
    
        if  (NULL == q->front->next) {
            q->rear = NULL;
        }
    
        front = q->front;
        q->front = q->front->next;
    
        *e = front->data;
    
        free(front);
    
        return 0;
    }
    void BFS(AMGraph G, int v)        //广度优先遍历
    {
        int i, j;
        LinkQueue Q;
        Q =(LinkQueue)malloc(sizeof(LinkQueue));
        InitQuene(Q);//采用的是链队列
        for (i = 0; i < G.vexnum; i++)
            visited[i] = false;
        for (i = 0; i < G.vexnum; i++)
        {
            if (visited[i] == false)
            {
                cout << setw(8) << G.vexs[v]; visited[v] = true;    //访问第v个顶点,并置visited数组对应值为true
    
                EnQueue(Q, v);    //v进队
                while (!QueueEmpty(Q))    //队列非空
                {
                    DeQueue(Q, &i);//队头元素出队,并置为i
                    for (j = 0; j < G.vexnum; j++)
                    {
                        if ((G.arcs[i][j] = !MaxInt || G.arcs[i][j] != 0) && visited[j] == false)
                        {//检查i的所有邻接点
                            visited[j] = true;
                            cout << setw(8) << G.vexs[j];//访问j
                            EnQueue(Q, j);//j入队
                        }
                    }
                }
            }
        }
    }

    BFS算法效率分析:
    (1)如果使用邻接矩阵,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行( n 个元素),总的时间代价为O(n2)。
    (2)用邻接表来表示图,虽然有 2e 个表结点,但只需扫描 e 个结点即可完成遍历,加上访问 n个头结点的时间,时间复杂度为O(n+e)。

    3.DFS与BFS算法效率比较
    (1)空间复杂度相同,都是O(n)(借用了堆栈或队列);
    (2)时间复杂度只与存储结构(邻接矩阵或邻接表)有关,而与搜索路径无关。

    四、最短路径算法(Dijkstra算法)
    最短路径:在带权有向图中A点(源点)到达B点(终点)的多条路径中,寻找一条各边权值之和最小的路径,即最短路径。
    辅助结构:
    数组S[n]:记录相应顶点是否已被确定最短距离
    数组Dist[n]:记录源点到相应顶点路径长度
    数组Path[n]:记录相应顶点的前驱顶点

    【Dijkstra算法思想】
    (1) 初始化:
    ● 将源点v0加到S中,即S[v0]=true
    ● 将v0到各个终点的最短路径长度初始化为权值,即Dist[i]=G.arcs[v0][vi]
    ● 如果v0和顶点vi之间有弧,则将vi的前驱置为v0,即Path[i]=v0,否则Path[i]=-1
    (2) 循环n-1次执行以下操作:
    ● 选择下一条最短路径的终点vk,使得Dist[k]=Min{Dist[i]|vi∈V-S}
    ● 将vk加入到S中,即S[vk]=true
    ● 根据条件更新从v0出发到集合V-S上任一顶点的最短路径的长度,若条件Dist[k]+G.arcs[k][i]<Dist[i]成立,则更新Dist[i]=Dist[k]+G.arcs[k][i],同时更改vi的前驱为vk;Path[i]=k

    算法思想:

     算法流程图

    Dijkstra算法代码实现:
    int Dist[MVNum];//Dist存当前找到的最短路径长度
    int Path[MVNum];//当前找到的最短路径最后一个中转顶点
    bool S[MVNum];//标记当前是否已求出最短路径
    void ShortestPath_DIJ(AMGraph G, int v0)//求有向网G的v0顶点到其余顶点的最短路径
    {
        int n, v, i, w, min;
        n = G.vexnum;//顶点数
        for (v = 0; v < n; v++) //n个顶点依次初始化 
        {
            S[v] = false;//S初始为空集 
            Dist[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值
            if (Dist[v] < MaxInt) Path[v] = v0;//如果v0与v之间有弧,则将v的前驱置为v0
            else Path[v] = -1;//无弧,置为-1 
        }
        S[v0] = true;//将v0加入S
        Dist[v0] = 0;//原点到原点 的距离为0
        //******初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加入到S集
        for (i = 1; i < n; i++)//n-1个顶点 
        {
            min = MaxInt;
            for (w = 0; w < n; w++)
                if (!S[w] && Dist[w] < min)//选择一条当前的最短路径,终点为v 
                {
                    v = w; min = Dist[w];
                }
            S[v] = true;//将v加入S 
            for (w = 0; w < n; ++w)//更新从v0出发到集合V-S上所有的最短路径长度 
                if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w])
                {
                    Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w] 
                    Path[w] = v;//更改w的前驱为v 
                }
        }
    }

    显示函数1:输入起点和终点,输出最短路径

    void DisplayPath(AMGraph G, int begin, int temp)
    {
        if (Path[temp] != -1)
        {
            DisplayPath(G, begin, Path[temp]);
            cout << G.vexs[Path[temp]] << "-->";
        }
    }

    显示函数2:输入源点,输出源点到其他各个顶点的最短路径

    void PrintPath(AMGraph G, int v)
    {
        int i, j, w;
        int road[MVNum];//用于存储最短路径顶点的下标
        for (i = 0; i < MVNum; i++)road[i] = -1;
        for (i = 0; i < G.vexnum; i++)
        {
            if ((S[i] == true) && (i != v))
            {
                cout << "" << G.vexs[v] << "" << G.vexs[i] << "的最短路径为:" <<  "\t\t"<<Dist[i] <<"\t\t";
                cout << G.vexs[v] << "->";
                w = Path[i];//最短路径途径的顶点
                j = 0;//为实现逆转标记途径顶点数
                while (w != v)//回溯途径顶点
                {
                    road[j] = w;
                    j++;
                    w = Path[w];
                }
                for (j=j-1; j >= 0; j--)//输出最短路径
                {
                    cout << G.vexs[road[j]] << "->";
                    road[j] = -1;
                }
                cout << G.vexs[i] << endl;
            }
            else
                cout << "" << G.vexs[v] << "" << G.vexs[i] << "不存在路径" << endl;
        }
    }

    五、具体实验

     main函数

    int main()
    {
        AMGraph G;
        VerTexType start, destination;    //声明起点和终点
        int num_start, num_destination;    //起点和终点在顶点表中的位置
        VerTexType v;
        int num_v;
        int choose = -1;
        cout << "**********************************" << endl;
        cout << "* 1.创建图" << endl;
        cout << "* 2.显示图的信息" << endl;
        cout << "* 3.图的深度优先遍历" << endl;
        cout << "* 4.图的广度优先遍历" << endl;
        cout << "* 5.输入起点和终点,显示最短路径" << endl;
        cout << "* 6.显示源点到各个顶点的最短路径" << endl;
        cout << "* 7.退出" << endl;
        cout << "**********************************" << endl;
    
        while (choose != 0)
        {
            cout << "\n----------------------- \n";
            
            cout<<"\n请输入操作序号:";
            cin >> choose;
            cout << endl;
            switch (choose)
            {
            case 1:
                CreateUDN(G);
                break;
            case 2:
                PrintGraph(G);
                break;
            case 3:
                cout << "深度优先遍历:" << endl;        
                DFS_AM(G, 0);
                break;
            case 4:
                cout << "广度优先遍历:" << endl;
                BFS(G);
                break;
            case 5:
                
                cout << "请依次输入起始点、终点名称:";
                cin >> start >> destination;
                //计算起点与终点编号 
                num_start = LocateVex(G, start);
                num_destination = LocateVex(G, destination);
                ShortestPath_DIJ(G, num_start);
                cout << endl << "最短路径为:";
                DisplayPath(G, num_start, num_destination);
                cout << G.vexs[num_destination] << endl;
                break;
            case 6:
                cout << "请输入源点:";
                cin >> v;
                num_v = LocateVex(G, v);
                ShortestPath_DIJ(G, num_v);
                PrintPath(G, num_v);
                break;
            case 7:
                exit_1();
                break;
            }
        }
        return 0;    
    }

     

     

     注:本文部分算法源自《数据结构(C语言版)》第二版 严蔚敏 人民邮电出版社

    完整代码,测试通过。

    // https://blog.csdn.net/qq_45694646/article/details/106764026
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <string>
    
    #include <sstream>
    #include <iostream>
    #include <iomanip>
    
    
    
    using namespace std;
    
    
    #define MaxInt 32767        //表示极大值 即无穷大
    #define MVNum 100            //最大顶点数
    typedef string VerTexType;    //设顶点的数据类型为string,需#include<string>
    typedef int ArcType;        //设权值类型为整型
    
    typedef struct
    {
        VerTexType vexs[MVNum];        //顶点表
        ArcType arcs[MVNum][MVNum];    //邻接矩阵
        int vexnum, arcnum;            //图的当前点数和边数
    }AMGraph;
    
    int LocateVex(AMGraph G, VerTexType u);
    
    bool CreateUDN(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j, k ;
        VerTexType v1, v2;
        ArcType w;
        cout << "请输入图的顶点总数和边的总数:";
        cin >> G.vexnum >> G.arcnum;    //输入总顶点数,总边数
        cout << "请依次输入顶点信息:" << endl;
        for (i = 0; i < G.vexnum; ++i)
            cin >> G.vexs[i];            //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
        cout << "请输入边的信息,格式:头,尾,权值" << endl;
        for (k = 0; k < G.arcnum; ++k)
        {
            cin >> v1 >> v2 >> w;        //输入一条边依附的顶点及权值
            i = LocateVex(G, v1);j= LocateVex(G, v2);        //确定v1,v2在G中的位置,即顶点数组的下标
            G.arcs[i][j] = w;        //边<v1,v2>的权值为w
            G.arcs[j][i] = G.arcs[i][j];    //对称边
        }
        return true;
    }
    
    int LocateVex(AMGraph G, VerTexType u)
    {//存在则返回u在顶点表中的下标;否则返回-1
        int i;
        for (i = 0; i < G.vexnum; ++i)
            if (u == G.vexs[i])
                return i;
        return -1;
    }
    
    void PrintGraph(AMGraph G)
    {
        int i, j;
        cout << "图的邻接矩阵存储信息:" << endl;
        cout << "顶点信息:" << endl;
        for (i = 0; i < G.vexnum; i++)
            cout << i << ":" << G.vexs[i] << endl;    //输出顶点信息
        cout << "邻接矩阵数据:" << endl;
        for (i = 0; i < G.vexnum; i++)
        {
            for (j = 0; j < G.vexnum; j++)
            {
                if (G.arcs[i][j] == MaxInt)
                    cout << left<<setw(6)<<"";
                else
                    cout << left<<setw(6) << G.arcs[i][j];
            }
            cout << endl;
        }
    }
    
    bool visited[MVNum] = {false};        //顶点表
    
    void DFS_AM(AMGraph G, int v)    //深度优先搜索遍历,从第v个顶点开始
    {
        cout <<setw(8)<< G.vexs[v]; visited[v] = true;    //访问第v个顶点,并置visited数组对应的值为true
        for (int w = 0; w < G.vexnum; w++)
            if ((G.arcs[v][w] != 0) && (!visited[w]))
                DFS_AM(G,w);        //G.arcs[v][w] != 0表示w是v的邻接点,如果w未访问,则递归调用DFS_AM
    }
    
    
    #if 1
    //队列的DAT//
    typedef int Elemtype; //BFS中队列存放的是图元素下标
    typedef int Status;
    typedef struct QNode {
        Elemtype data;
        struct QNode* next;
    }*QueuePrt;
    
    typedef struct {
        QueuePrt front, rear;    //指针形式的对头和队尾指针
    }LinkQueue_T;
    
    typedef struct LinkQueue_t{
        QueuePrt front, rear;    //指针形式的对头和队尾指针
    }*LinkQueue;
    
    Status InitQuene(LinkQueue q)
    {
        if (NULL == q) {
            return -1;
        }
    
        q->front = NULL;
        q->rear = NULL;
    
        return 0;
    }
    
    bool QueueEmpty(LinkQueue Q)
    {
        if (NULL == Q) {
            return true;
        }
    
    
        if (NULL == Q->front)
        {
            return true;
        }
    
        return false;
    }
    
    Status EnQueue(LinkQueue q, Elemtype e)
    {
        QueuePrt QP = NULL;
    
        if (NULL == q) {
            return -1;
        }
    
        QP = (QueuePrt)calloc(1, sizeof(struct QNode));
    
        QP->data = e;
        QP->next = NULL;
    
        if (NULL == q->front) {
            q->front = QP;
            q->rear = QP;
        } else {
            q->rear->next = QP;
            q->rear = QP;
        }
    
        return 0;
    }
    
    Status DeQueue(LinkQueue q, Elemtype *e)
    {
        QueuePrt QP = NULL;
        QueuePrt QP_prev = NULL;
        QueuePrt front = NULL;
    
        if (NULL == q || NULL == e) {
            return -1;
        }
    
    
        if (QueueEmpty(q)) {
            return 0;
        }
    
        if  (NULL == q->front->next) {
            q->rear = NULL;
        }
    
        front = q->front;
        q->front = q->front->next;
    
        *e = front->data;
    
        free(front);
    
        return 0;
    }
    
    
    void BFS(AMGraph G, int v)        //广度优先遍历
    {
        int i = 0;
        int j = 0;
        LinkQueue Q = NULL;
    
        Q = (LinkQueue)calloc(1, sizeof(struct LinkQueue_t));
    
        InitQuene(Q); // 采用的是链队列
    
        for (i = 0; i < G.vexnum; i++) {
            visited[i] = false;
        }
    
        for (i = 0; i < G.vexnum; i++)
        {
            if (visited[i] == false)
            {
                cout << setw(8) << G.vexs[v]; visited[v] = true;    //访问第v个顶点,并置visited数组对应值为true
    
                // cout << v << endl;
    
                EnQueue(Q, v);    //v进队
                while (!QueueEmpty(Q))    //队列非空
                {
                    DeQueue(Q, &i);//队头元素出队,并置为i
                   // cout << "222" << endl;
                    for (j = 0; j < G.vexnum; j++)
                    {
                        if ((G.arcs[i][j] != MaxInt && G.arcs[i][j] != 0) && visited[j] == false)
                        {//检查i的所有邻接点
                            visited[j] = true;
                            cout << setw(8) << G.vexs[j];//访问j
                            EnQueue(Q, j);//j入队
                        }
                    //cout << "231" << endl;
                    }
                }
            }
        }
    }
    #endif
    
    
    int Dist[MVNum];//Dist存当前找到的最短路径长度
    int Path[MVNum];//当前找到的最短路径最后一个中转顶点
    bool S[MVNum];//标记当前是否已求出最短路径
    void ShortestPath_DIJ(AMGraph G, int v0)//求有向网G的v0顶点到其余顶点的最短路径
    {
        int n, v, i, w, min;
        n = G.vexnum;//顶点数
        for (v = 0; v < n; v++) //n个顶点依次初始化
        {
            S[v] = false;//S初始为空集
            Dist[v] = G.arcs[v0][v];//将v0到各个终点的最短路径长度初始化为弧上的权值
            if (Dist[v] < MaxInt) Path[v] = v0;//如果v0与v之间有弧,则将v的前驱置为v0
            else Path[v] = -1;//无弧,置为-1
        }
        S[v0] = true;//将v0加入S
        Dist[v0] = 0;//原点到原点 的距离为0
        //******初始化结束,开始主循环,每次求得v0到某个顶点v的最短路径,将v加入到S集
        for (i = 1; i < n; i++)//n-1个顶点
        {
            min = MaxInt;
            for (w = 0; w < n; w++)
                if (!S[w] && Dist[w] < min)//选择一条当前的最短路径,终点为v
                {
                    v = w; min = Dist[w];
                }
            S[v] = true;//将v加入S
            for (w = 0; w < n; ++w)//更新从v0出发到集合V-S上所有的最短路径长度
                if (!S[w] && (Dist[v] + G.arcs[v][w]) < Dist[w])
                {
                    Dist[w] = Dist[v] + G.arcs[v][w];//更新D[w]
                    Path[w] = v;//更改w的前驱为v
                }
        }
    }
    
    void DisplayPath(AMGraph G, int begin, int temp)
    {
        if (Path[temp] != -1)
        {
            DisplayPath(G, begin, Path[temp]);
            cout << G.vexs[Path[temp]] << "-->";
        }
    }
    
    void PrintPath(AMGraph G, int v)
    {
        int i, j, w;
        int road[MVNum];//用于存储最短路径顶点的下标
        for (i = 0; i < MVNum; i++)road[i] = -1;
        for (i = 0; i < G.vexnum; i++)
        {
            if ((S[i] == true) && (i != v))
            {
                cout << "" << G.vexs[v] << "" << G.vexs[i] << "的最短路径为:" <<  "\t\t"<<Dist[i] <<"\t\t";
                cout << G.vexs[v] << "->";
                w = Path[i];//最短路径途径的顶点
                j = 0;//为实现逆转标记途径顶点数
                while (w != v)//回溯途径顶点
                {
                    road[j] = w;
                    j++;
                    w = Path[w];
                }
                for (j=j-1; j >= 0; j--)//输出最短路径
                {
                    cout << G.vexs[road[j]] << "->";
                    road[j] = -1;
                }
                cout << G.vexs[i] << endl;
            }
            else
                cout << "" << G.vexs[v] << "" << G.vexs[i] << "不存在路径" << endl;
        }
    }
    
    Status add_edge(AMGraph &G, VerTexType v1, VerTexType v2, ArcType w)
    {
        int i = 0;
        int j = 0;
    
        i = LocateVex(G, v1);j= LocateVex(G, v2);       //确定v1,v2在G中的位置,即顶点数组的下标
        G.arcs[i][j] = w;       //边<v1,v2>的权值为w
        G.arcs[j][i] = G.arcs[i][j];    //对称边
    
        return 0;
    }
    
    bool CreateUDN_test(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j ;
    
        //cout << "请输入图的顶点总数和边的总数:";
        G.vexnum = 10;
        G.arcnum = 12;    //输入总顶点数,总边数
    
        //cout << "请依次输入顶点信息:" << endl;
        G.vexs[0] = "昆明";
        G.vexs[1] = "成都";
        G.vexs[2] = "西安";
        G.vexs[3] = "郑州";
        G.vexs[4] = "徐州";
        G.vexs[5] = "上海";
        G.vexs[6] = "南昌";
        G.vexs[7] = "株洲";
        G.vexs[8] = "贵阳";
        G.vexs[9] = "武汉";
                    //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
    
        //cout << "请输入边的信息,格式:头,尾,权值" << endl;
    
        add_edge(G, "昆明", "成都", 1100); //输入一条边依附的顶点及权值
        add_edge(G, "成都", "西安", 842 ); //输入一条边依附的顶点及权值
        add_edge(G, "西安", "郑州", 511 ); //输入一条边依附的顶点及权值
        add_edge(G, "郑州", "徐州", 349 ); //输入一条边依附的顶点及权值
        add_edge(G, "徐州", "上海", 651 ); //输入一条边依附的顶点及权值
        add_edge(G, "上海", "南昌", 825 ); //输入一条边依附的顶点及权值
        add_edge(G, "南昌", "株洲", 367 ); //输入一条边依附的顶点及权值
        add_edge(G, "株洲", "贵阳", 902 ); //输入一条边依附的顶点及权值
        add_edge(G, "贵阳", "昆明", 639 ); //输入一条边依附的顶点及权值
        add_edge(G, "成都", "贵阳", 967 ); //输入一条边依附的顶点及权值
        add_edge(G, "郑州", "武汉", 534 ); //输入一条边依附的顶点及权值
        add_edge(G, "武汉", "株洲", 409 ); //输入一条边依附的顶点及权值
    
        return true;
    }
    
    
    bool CreateUDN_test2(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j ;
    
        //cout << "请输入图的顶点总数和边的总数:";
        G.vexnum = 10;
        G.arcnum = 12;    //输入总顶点数,总边数
    
        //cout << "请依次输入顶点信息:" << endl;
        G.vexs[0] = "西安";
        G.vexs[1] = "郑州";
        G.vexs[2] = "徐州";
        G.vexs[3] = "上海";
        G.vexs[4] = "南昌";
        G.vexs[5] = "株洲";
        G.vexs[6] = "贵阳";
        G.vexs[7] = "昆明";
        G.vexs[8] = "成都";
        G.vexs[9] = "武汉";
                    //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
    
        //cout << "请输入边的信息,格式:头,尾,权值" << endl;
    
        add_edge(G, "西安", "郑州", 511 ); //输入一条边依附的顶点及权值
        add_edge(G, "郑州", "徐州", 349 ); //输入一条边依附的顶点及权值
        add_edge(G, "郑州", "武汉", 534 ); //输入一条边依附的顶点及权值
        add_edge(G, "徐州", "上海", 651 ); //输入一条边依附的顶点及权值
        add_edge(G, "上海", "南昌", 825 ); //输入一条边依附的顶点及权值
        add_edge(G, "南昌", "株洲", 367 ); //输入一条边依附的顶点及权值
        add_edge(G, "武汉", "株洲", 409 ); //输入一条边依附的顶点及权值
        add_edge(G, "株洲", "贵阳", 902 ); //输入一条边依附的顶点及权值
        add_edge(G, "贵阳", "昆明", 639 ); //输入一条边依附的顶点及权值
        add_edge(G, "成都", "贵阳", 967 ); //输入一条边依附的顶点及权值
        add_edge(G, "昆明", "成都", 1100); //输入一条边依附的顶点及权值
        add_edge(G, "成都", "西安", 842 ); //输入一条边依附的顶点及权值
    
        return true;
    }
    
    
    bool CreateUDN_test3(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j ;
    
        //cout << "请输入图的顶点总数和边的总数:";
        G.vexnum = 7; //输入总 顶点数
        G.arcnum = 6; //输入总 边数
    
        //cout << "请依次输入顶点信息:" << endl;
        G.vexs[0] = "A";
        G.vexs[1] = "B";
        G.vexs[2] = "C";
        G.vexs[3] = "D";
        G.vexs[4] = "E";
        G.vexs[5] = "F";
        G.vexs[6] = "C.1";
    
                    //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
    
        //cout << "请输入边的信息,格式:头,尾,权值" << endl;
    
        add_edge(G, "A", "B", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "B", "C", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C", "D", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "D", "E", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "E", "F", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C", "C.1", 1 ); //输入一条边依附的顶点及权值
    
        return true;
    }
    
    
    
    bool CreateUDN_test4(AMGraph& G)        //采用邻接矩阵表示法,创建无向网
    {
        int i, j ;
    
        //cout << "请输入图的顶点总数和边的总数:";
        G.vexnum = 10; //输入总 顶点数
        G.arcnum = 9; //输入总 边数
    
        //cout << "请依次输入顶点信息:" << endl;
        G.vexs[0] = "A";
        G.vexs[1] = "B";
        G.vexs[2] = "C";
        G.vexs[3] = "D";
        G.vexs[4] = "E";
        G.vexs[5] = "F";
        G.vexs[6] = "C.1";
        G.vexs[7] = "C.2";
        G.vexs[8] = "C.3";
        G.vexs[9] = "C.1.1";
    
                    //依次输入顶点信息
        for (i = 0; i < G.vexnum; ++i)
            for (j = 0; j < G.vexnum; ++j)
                G.arcs[i][j] = MaxInt;//初始化邻接矩阵,置为无穷大
    
        //cout << "请输入边的信息,格式:头,尾,权值" << endl;
    
        add_edge(G, "A", "B", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "B", "C", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C", "D", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "D", "E", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "E", "F", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C", "C.1", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C.1", "C.2", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C.2", "C.3", 1 ); //输入一条边依附的顶点及权值
        add_edge(G, "C.1", "C.1.1", 1 ); //输入一条边依附的顶点及权值
    
        return true;
    }
    int main(int argc, char *argv[])
    {
        AMGraph G;
        VerTexType start, destination;    //声明起点和终点
        int num_start, num_destination;    //起点和终点在顶点表中的位置
        VerTexType v;
        int num_v;
        int choose = -1;
        cout << "**********************************" << endl;
        cout << "* 1.创建图" << endl;
        cout << "* 2.显示图的信息" << endl;
        cout << "* 3.图的深度优先遍历" << endl;
        cout << "* 4.图的广度优先遍历" << endl;
        cout << "* 5.输入起点和终点,显示最短路径" << endl;
        cout << "* 6.显示源点到各个顶点的最短路径" << endl;
        cout << "* 7.退出" << endl;
        cout << "**********************************" << endl;
    
        CreateUDN_test4(G);
    
        while (choose != 0)
        {
            cout << "\n----------------------- \n";
    
            cout<<"\n请输入操作序号:";
            cin >> choose;
            cout << endl;
            switch (choose)
            {
            case 1:
                CreateUDN(G);
                break;
            case 2:
                PrintGraph(G);
                break;
            case 3:
                cout << "深度优先遍历:" << endl;
                DFS_AM(G, 0);
                break;
            case 4:
                cout << "广度优先遍历:" << endl;
                BFS(G, 0);
                break;
            case 5:
    
                cout << "请依次输入起始点、终点名称:";
                cin >> start >> destination;
                //计算起点与终点编号
                num_start = LocateVex(G, start);
                num_destination = LocateVex(G, destination);
                ShortestPath_DIJ(G, num_start);
                cout << endl << "最短路径为:";
                DisplayPath(G, num_start, num_destination);
                cout << G.vexs[num_destination] << endl;
                break;
            case 6:
                cout << "请输入源点:";
                cin >> v;
                num_v = LocateVex(G, v);
                ShortestPath_DIJ(G, num_v);
                PrintPath(G, num_v);
                break;
            case 7:
                exit(0);
                break;
            }
        }
        return 0;
    }
  • 相关阅读:
    每日日报
    剑指 Offer 18. 删除链表的节点(LeetCode)
    java的访问权限
    java从键盘输入
    剑指 Offer 22. 链表中倒数第k个节点(快慢指针)(LeetCode)
    面试题 02.03. 删除中间节点(LeetCode)
    21. 合并两个有序链表(Leetcode)
    计算总线数据传输率
    时钟周期、总线周期(机器周期)区别
    书单(个人)
  • 原文地址:https://www.cnblogs.com/LiuYanYGZ/p/16317836.html
Copyright © 2020-2023  润新知