c++ 由無向圖構造鄰接表,實現深度優先遍歷、廣度優先遍歷。


/*
首先,根據用戶輸入的頂點總數和邊數,構造無向圖,然后以用戶輸入的頂點
為起始點,進行深度優先、廣度優先搜索遍歷,並輸出遍歷的結果。
*/
#include <stdlib.h>
#include <iostream>
#define MVNum 100         //最大的頂點數
using namespace std;

/*——————圖的鄰接表存儲表示——————*/
//邊的結點表-在頂點表后面
typedef struct ArcNode
{
    int adjvex;                 //鄰接點域-該邊所指向頂點的位置下標
    struct ArcNode* nextarc; //鏈域-鄰接的下一頂點位置
    //otherInfo info;        //用來紀錄權值
}ArcNode;
//單鏈表表頭-結構體(類似於頭結點)
typedef struct VNode
{
    char data;                //頂點的信息值
    ArcNode* firstarc;        //指向第一條依附該頂點的下一結點-指向類型為邊ArcNode
}VNode, AdjList[MVNum];        //AdjList鄰接表類型
//圖ALGraph
typedef struct
{
    AdjList vertices;        //定義一個鄰接表類型,vertices最多有MVNum個
    int vexnum;                //頂點數
    int arcnum;                //邊數
}ALGraph;
//鏈隊列結構體
typedef struct QNode
{
    int data;
    struct QNode* next;
}QNode,*QueuePtr;
//鏈隊頭指針結構體
typedef struct
{
    QueuePtr front;  //隊頭
    QueuePtr rear;      //隊尾
}LinkQueue;
//尋找v1,v2的下標
int LocateVex(ALGraph& G, char NodeInfo)
{
    int flag = 0;
    //匹配NodeInfo
    for (int i = 0; i < G.vexnum; i++)
    {
        if (G.vertices[i].data == NodeInfo)
        {
            flag = i;
            return i;
            break;
        }
    }
    if (flag)
        return flag;
    else
        exit(errno);
}
//鄰接表生成無邊圖
void CreateUDG(ALGraph& G)
{
    //輸入數據
    cout << "請輸入相應的頂點數與邊數(以空格間隔):" << endl;
    cin >> G.vexnum >> G.arcnum;

    //初始化頂點信息
    cout << "請輸入" << G.vexnum << "個頂點的信息(以空格間隔):" << endl;
    for (int i = 0; i < G.vexnum; i++)
    {
        cin >> G.vertices[i].data;
        G.vertices[i].firstarc = NULL;    //各頂點結點的指針域置空
    }

    //初始化邊的連接信息
    for (int i = 0; i < G.arcnum; i++)
    {
        char v1, v2;                        //v1,v2為一條邊連接的兩個頂點
        cout << "請輸入第" << i << "條邊的兩頂點信息(以空格間隔):";
        cin >> v1 >> v2;

        //求v1,v2在vertices的下標
        int idx_v1 = LocateVex(G, v1);
        int idx_v2 = LocateVex(G, v2);

        //調用邊的結點表,生成以v1為頭結點的單鏈表構成的鄰接表
        ArcNode* p1 = new ArcNode;            //生成第一個邊連接的結點(后面的那一個)
        p1->adjvex = idx_v2;                //存入結點的下標
        //關聯頭結點,用頭插法,插入結點
        p1->nextarc = G.vertices[idx_v1].firstarc;
        G.vertices[idx_v1].firstarc = p1;

        //調用邊的結點表,生成以v2為頭結點的單鏈表構成的鄰接表
        ArcNode* p2 = new ArcNode;            //生成第一個邊連接的結點(后面的那一個)
        p2->adjvex = idx_v1;                //存入結點的下標
        //關聯頭結點,用頭插法,插入結點
        p2->nextarc = G.vertices[idx_v2].firstarc;
        G.vertices[idx_v2].firstarc = p2;
    }
}
//鄰接表的遍歷
void TraverseAdjList(ALGraph& G)
{
    for (int i = 0; i < G.vexnum; i++)
    {
        cout << "" << G.vertices[i].data << "】→";
        //臨時頭指針用於遍歷
        ArcNode* temp = G.vertices[i].firstarc;
        //當temp不為空,輸出鏈表

        while (temp)
        {
            //輸出頂點序號
            cout<<"["<<temp->adjvex<<"]";
            temp=temp->nextarc;
            if (temp)
                cout << "";
        }
        putchar(10);
    }
}
//深度優先遍歷
int visisted_D[MVNum] = { 0 };    //輔助數組
void DFS_AL(ALGraph& G, int v)
{
    //從v頂點開始訪問
    cout <<"("<< G.vertices[v].data <<")";
    //訪問過后置1
    visisted_D[v] = 1;
    //臨時結點用於遍歷,指向頭結點后一結點
    ArcNode *temp = G.vertices[v].firstarc;

    //循環遍歷
    while (temp)
    {
        int w = temp->adjvex;
        //如果輔助數組visisted[w] == 0遞歸調用DFS_AL
        if (visisted_D[w] == 0)
        {
            DFS_AL(G, w);
        }
        //temp指向下一結點
        temp = temp->nextarc;
    }
}
//廣度優先遍歷
int visisted_B[MVNum] = { 0 };    //輔助數組
//隊列初始化
void InitQuenue(LinkQueue& Q)
{
    Q.rear = new QNode;
    Q.front = Q.rear;
    Q.front->next = NULL;
}
//入隊-尾插法
void EnQuenue(LinkQueue& Q,int v)
{
    QNode* cur = new QNode;
    cur->data = v;
    cur->next = NULL;
    Q.rear->next = cur;
    Q.rear = cur;
}
//出隊-返回隊頭int u
void DeQuenue(LinkQueue& Q, int &u)
{
    QNode* temp = Q.front->next;
    Q.front->next = temp->next;
    //隊頭u更新
    u = temp->data;
    //如果最后一個被刪,隊尾指向隊頭
    if (Q.rear == temp)
    {
        Q.rear = Q.front;
    }
    delete temp;
}
//返回u的第一個鄰結點
int FirstAdjvex(ALGraph& G, int u)
{
    int w = G.vertices[u].firstarc->adjvex;
    return w;
}
//返回u的下一個鄰結點
int NextAdjVex(ALGraph& G, int u, int w)
{
    //臨時結點temp指向頭結點的第一個鄰結點,w此時為第一結點序號
    ArcNode *temp = G.vertices[u].firstarc;
    while (temp->adjvex != w)
    {
        temp = temp->nextarc;
    }
    //若w結點的下一結點不為空,返回結點序號w的下一結點序號
    if (temp->nextarc)
        return temp->nextarc->adjvex;
    //否則返回-1,使其退出循環
    else 
        return -1;
    delete temp;
}
void BFS_AL(ALGraph& G, int v)
{
    //從v頂點開始訪問
    cout << "(" << G.vertices[v].data << ")";
    //訪問過后置1
    visisted_B[v] = 1;
    //創建隊列
    LinkQueue Q;
    InitQuenue(Q);
    EnQuenue(Q,v);
    int u = v;        //用於找鄰接點
    //隊列非空出隊
    while (Q.rear != Q.front)
    {
        //出隊,並把隊頭置為u
        DeQuenue(Q, u);
        for (int w = FirstAdjvex(G, u); w >= 0; w = NextAdjVex(G, u, w))
        {
            //若結點序號w未訪問則進行訪問
            if (!visisted_B[w])
            {
                cout << "(" << G.vertices[w].data << ")";        //輸出數據
                visisted_B[w] = 1;                //打上訪問標記
                EnQuenue(Q, w);                    //將結點w入隊
            }
        }//進行下一次w的鄰結點查找
    }
}
void main()
{
    ALGraph G;
    //鄰接表生成無邊圖

    CreateUDG(G);
    //遍歷鄰接表
    TraverseAdjList(G);
    //深度優先遍歷
    cout << "請問從第幾個頂點開始深度優先遍歷:";
    int v;
    cin >> v;
    cout << "DFS:";
    DFS_AL(G, v-1);
    putchar(10);
    //廣度優先遍歷
    cout << "請問從第幾個頂點開始廣度優先遍歷:";
    cin >> v;
    cout << "BFS:";
    BFS_AL(G, v - 1);
    putchar(10);
    system("pause");
}

//深度優先遍歷由遞歸實現。也可用棧來實現(與BFS隊列操作類似)。

//廣度優先遍歷由隊列實現。需要先讓開始進行遍歷的頂點入隊,再進行出隊,但是出隊需保存出隊的結點序號值作為表頭,用於遍歷該層,並同時將輔助數組visisted_B[v]置為1,以表示已經訪問,然后根據鄰接表結構進行類似於樹的層次遍歷操作,每個結點訪問過后都要將visisted_B[v]置為1,當其中一層遍歷完過后,先進的第一個結點出隊,並更新出隊值,同時開始遍歷以該結點序號為頭結點的單鏈表,直到每層遍歷完后結束。
//在廣度優先遍歷過程中,進行出隊操作時,一開始用形參int u來進行接收,導致隊頭值u(表頭)無法更新,造成只能遍歷初始頂點的那一條單鏈表,后改為形參 int &u解決隊頭值更新問題。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM