1. 程式人生 > 其它 >C++實現圖的遍歷和最短路徑

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