C語言實現數據結構的鄰接矩陣----數組生成矩陣、打印、深度優先遍歷和廣度優先遍歷


 

寫在前面

  圖的存儲結構有兩種:一種是基於二維數組的鄰接矩陣表示法。

            另一種是基於鏈表的的鄰接表表示法。

  在鄰接矩陣中,可以如下表示頂點和邊連接關系:

    

說明:

  將頂點對應為下標,根據橫縱坐標將矩陣中的某一位置值設為1,表示兩個頂點向聯接。

  圖示表示的是無向圖的鄰接矩陣,從中我們可以發現它們的分布關於斜對角線對稱

  我們在下面將要討論的是下圖的兩種遍歷方法(基於矩陣的):

     

  我們已經說明了我們要用到的是鄰接矩陣表示法,那么我首先要來構造圖:

 

 

1.深度優先遍歷算法

  分析深度優先遍歷

    從圖的某個頂點出發,訪問圖中的所有頂點且使每個頂點僅被訪問一次。這一過程叫做圖的遍歷。

    深度優先搜索的思想:

      ①訪問頂點v;
      ②依次從v的未被訪問的鄰接點出發,對圖進行深度優先遍歷;直至圖中和v有路徑相通的頂點都被訪問;
      ③若此時圖中尚有頂點未被訪問,則從一個未被訪問的頂點出發,重新進行深度優先遍歷,直到圖中所有頂點均被訪問過為止。

    比如:

    

    在這里為了區分已經訪問過的節點和沒有訪問過的節點,我們引入一個一維數組bool visited[MaxVnum]用來表示與下標對應的頂點是否被訪問過,

流程:
☐ 首先輸出 V1,標記V1的flag=true;
☐ 獲得V1的鄰接邊 [V2 V3],取出V2,標記V2的flag=true;
☐ 獲得V2的鄰接邊[V1 V4 V5],過濾掉已經flag的,取出V4,標記V4的flag=true;
☐ 獲得V4的鄰接邊[V2 V8],過濾掉已經flag的,取出V8,標記V8的flag=true;
☐ 獲得V8的鄰接邊[V4 V5],過濾掉已經flag的,取出V5,標記V5的flag=true;
☐ 此時發現V5的所有鄰接邊都已經被flag了,所以需要回溯。(左邊黑色虛線,回溯到V1,回溯就是下層遞歸結束往回返)
☐ 
☐ 回溯到V1,在前面取出的是V2,現在取出V3,標記V3的flag=true;
☐ 獲得V3的鄰接邊[V1 V6 V7],過濾掉已經flag的,取出V6,標記V6的flag=true;
☐ 獲得V6的鄰接邊[V3 V7],過濾掉已經flag的,取出V7,標記V7的flag=true;
☐ 此時發現V7的所有鄰接邊都已經被flag了,所以需要回溯。(右邊黑色虛線,回溯到V1,回溯就是下層遞歸結束往回返)

 

  深度優先搜索的代碼

 

2.廣度優先搜索算法

  分析廣度優先遍歷    

    所謂廣度,就是一層一層的,向下遍歷,層層堵截,還是這幅圖,我們如果要是廣度優先遍歷的話,我們的結果是V1 V2 V3 V4 V5 V6 V7 V8。

      

    廣度優先搜索的思想:

       ① 訪問頂點vi ;

       ② 訪問vi 的所有未被訪問的鄰接點w1 ,w2 , …wk ;

       ③ 依次從這些鄰接點(在步驟②中訪問的頂點)出發,訪問它們的所有未被訪問的鄰接點; 依此類推,直到圖中所有訪問過的頂點的鄰接點都被訪問;

   說明:

      為實現③,需要保存在步驟②中訪問的頂點,而且訪問這些頂點的鄰接點的順序為:先保存的頂點,其鄰接點先被訪問。 這里我們就想到了用標准模板庫中的queue隊列來實現這種先進現出的服務。

      老規矩我們還是走一邊流程:

   說明: 

     ☐將V1加入隊列,取出V1,並標記為true(即已經訪問),將其鄰接點加進入隊列,則 <—[V2 V3] 

     ☐取出V2,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V3 V4 V5]

☐取出V3,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V4 V5 V6 V7]

☐取出V4,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V5 V6 V7 V8]

☐取出V5,並標記為true(即已經訪問),因為其鄰接點已經加入隊列,則 <—[V6 V7 V8]

☐取出V6,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V7 V8]

☐取出V7,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[V8]

☐取出V8,並標記為true(即已經訪問),將其未訪問過的鄰接點加進入隊列,則 <—[]

 

 

兩種表示法:

 

鄰接矩陣完整代碼:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
//鄰接矩陣
#define OK 1
#define ERROR 0

#define MAXNUM 10

typedef int Status;
typedef char ElemType;
typedef struct
{
    int vnum;    //頂點數
    int anum;    //弧/邊數
    ElemType vex[MAXNUM];    //存儲頂點
    int arc[MAXNUM][MAXNUM];    //存儲邊關系
}MGraph;

int Location(MGraph G, ElemType e)
{
    int v;
    for (v = 0; v<G.vnum; v++)
        if (G.vex[v] == e)return v;
    return -1;

}

Status CreateGraph(MGraph &G, int vnum, int anum, ElemType v[], ElemType a[])    //數組生成圖
{
    int k;
    G.vnum = vnum;    //獲取數組頂點數
    G.anum = anum;    //獲取數組邊數
    for (k = 0; k<G.vnum; k++)
        G.vex[k] = v[k];
    for (int i = 0; i<G.vnum; i++)
    {
        for (int j = 0; j<G.vnum; j++)
            G.arc[i][j] = 0;
    }
    int t = 0;
    int p, q;
    for (k = 0; k<G.anum; k++)
    {
        ElemType m, n;
        m = a[t++];
        n = a[t++];
        t++;
        p = Location(G, m);
        q = Location(G, n);
        G.arc[p][q] = 1;
        G.arc[q][p] = 1;
    }
    return OK;
}

void Print(MGraph G)
{
    int v;
    printf("頂點序列為:\n");
    for (v = 0; v<G.vnum; v++)
        printf("%3c", G.vex[v]);
    printf("\n");
    printf("邊的二維數組關系:\n");
    for (int i = 0; i<G.vnum; i++)
    {
        for (int j = 0; j<G.vnum; j++)
            printf("%3d", G.arc[i][j]);
        printf("\n");
    }
    printf("\n");
}

int FirstAdjVex(MGraph G, int i)
{
    int v;
    if (i<0 || i >= G.vnum)return -1;
    for (v = 0; v<G.vnum; v++)
        if (G.arc[i][v] == 1)return v;
    return -1;
}

int NextAdjVex(MGraph G, int i, int j)
{
    if (i<0 || i >= G.vnum)return -1;
    if (j<0 || j >= G.vnum)return -1;
    for (int v = j + 1; v<G.vnum; v++)
        if (G.arc[i][v] == 1)return v;
    return -1;
}

//DFS遍歷
int visited[MAXNUM];
void DFS(MGraph G, int v);
void DFSTraverse(MGraph G)
{
    printf("深度優先遍歷為:\n");
    int v;
    for (v = 0; v<G.vnum; v++)
        visited[v] = 0;
    for (v = 0; v<G.vnum; v++)
    {
        if (visited[v] == 0)DFS(G, v);
    }
}
void DFS(MGraph G, int v)
{
    printf("%3c", G.vex[v]);
    visited[v] = 1;
    int w = FirstAdjVex(G, v);
    while (w != -1)
    {
        if (visited[w] == 0)DFS(G, w);
        w = NextAdjVex(G, v, w);
    }
}

//BFS遍歷
typedef struct QNode
{
    ElemType data;
    struct QNode *next;
}QNode, *QueuePtr;    //定義隊列的指針類型為QueuePtr,定義隊列結點內存空間類型為QNode
typedef struct
{
    QueuePtr front;    //front為頭指針,指向頭結點。Q.front->next指針存在頭結點的指針域(即其存着首結點的地址),是頭結點的指針,指向首結點
    QueuePtr rear;
}LinkQueue;    //定義隊列結點類型為LinkQueue

Status InitQueue(LinkQueue &Q)
{
    Q.front = (QNode*)malloc(sizeof(QNode));
    if (!Q.front)return ERROR;
    Q.front->next = NULL;
    Q.rear = Q.front;
    return OK;
}

Status EnQueue(LinkQueue &Q, ElemType e)    //入隊
{
    QueuePtr p;
    p = (QNode*)malloc(sizeof(QNode));    //生成新結點p
    if (!p)return ERROR;
    p->next = NULL;    //新結點的指針p->next置空
    p->data = e;    //新結點暫存e
    Q.rear->next = p;    //隊尾結點的指針Q.rear->next指向新結點p
    Q.rear = p;    //隊尾指針Q.rear指向p
    return OK;
}

Status DeQueue(LinkQueue &Q, ElemType &e)    //出隊
{
    QueuePtr p;
    if (Q.rear == Q.front)    //確保隊列有首結點
        return ERROR;
    p = Q.front->next;    //指針p暫存被刪結點(首結點)的地址
    Q.front->next = p->next;    //頭結點的指針Q.front->next指向首結點的下一結點
    e = p->data;
    if (Q.front->next == Q.rear)    //判斷原隊列是否只有首結點
        Q.rear = Q.front;
    free(p);//清空
    return OK;
}

bool EmptyQueue(LinkQueue Q)    //判空
{
    if (Q.front == Q.rear)return true;
    else return false;
}

void BFS(MGraph G)
{
    printf("廣度優先遍歷為:\n");
    int v;
    LinkQueue Q;
    InitQueue(Q);
    for (v = 0; v<G.vnum; v++)    //初始化
        visited[v] = 0;
    for (v = 0; v<G.vnum; v++)
    {
        if (visited[v] == 1)continue;
        printf("%3c", G.vex[v]);
        visited[v] = 1;
        EnQueue(Q, G.vex[v]);
        while (EmptyQueue == 0)
        {
            int v;
            ElemType e;
            DeQueue(Q, e);
            v = Location(G, e);
            int w = FirstAdjVex(G, v);
            while (w != -1)
            {
                w = NextAdjVex(G, v, w);
                if (visited[w] = 1)continue;
                printf("%3c", G.vex[w]);
                EnQueue(Q, G.vex[w]);
                visited[w] = 1;
            }
        }
    }
}


int main()
{
    MGraph G;
    ElemType v[] = "abcdef";    //頂點數組
    ElemType a[] = "ab,ac,ad,be,ce,df";    //邊數組
    CreateGraph(G, 6, 6, v, a);
    Print(G);
    DFSTraverse(G);
    printf("\n");
    BFS(G);
    printf("\n");
    system("pause");
    return 0;
}//
View Code

 

鄰接表完整代碼:

#include<stdio.h>
#include<malloc.h>

#define OK 1
#define ERROR 0

#define MAXNUM 10

typedef int Status;
typedef char ElemType;
typedef struct ANode
{
    int adjvex;    //鄰接點域
    struct ANode *next;    //鄰接點指針域
}ANode;    //ANode為單鏈表的指針類型
typedef struct
{
    ElemType data;
    ANode *firstarc;    //定義單鏈表的頭指針為firstarc
}VNode;    //VNode為頂點數組元素的類型
typedef struct
{
    int vnum,anum;    //頂點數,邊數
    VNode vex[MAXNUM];    //頂點集
}ALGraph;    //ALGraph鄰接表類型

int Location(ALGraph G, ElemType e)
{
    int v;
    for (v = 0; v<G.vnum; v++)
        if (G.vex[v].data == e)return v;
    return -1;
}

Status CreatGraph(ALGraph &G, int vnum, int anum, ElemType v[], ElemType a[])
{
    int k, t = 0;
    G.vnum = vnum;
    G.anum = anum;
    for (k = 0; k<G.vnum; k++)
    {
        G.vex[k].data = v[k];
        G.vex[k].firstarc = NULL;//易忘記
    }
    for (k = 0; k<G.anum; k++)
    {
        ElemType m, n;
        ANode *p1, *p2, *p3;
        int p, q;
        m = a[t++];
        n = a[t++];
        t++;
        p = Location(G, m);
        q = Location(G, n);
        p1 = (ANode*)malloc(sizeof(ANode));
        if (p1 == NULL)return ERROR;
        p1->adjvex = q;
        p1->next = NULL;
        if (G.vex[p].firstarc == NULL)
            G.vex[p].firstarc = p1;
        else
        {
            p3 = G.vex[p].firstarc;
            while (p3->next)
                p3 = p3->next;
            p3->next = p1;
        }
        p2 = (ANode*)malloc(sizeof(ANode));
        if (!p2)return ERROR;
        p2->adjvex = p;
        p2->next = NULL;
        if (G.vex[q].firstarc == NULL)
            G.vex[q].firstarc = p2;
        else
        {
            p3 = G.vex[p].firstarc;
            while (p3->next)
                p3 = p3->next;
            p3->next = p2;
        }

    }
    return OK;
}

int FirstAdjVex(ALGraph G, int v)
{
    if (v<0 || v >= G.vnum)return -1;
    if (G.vex[v].firstarc != NULL)
        return G.vex[v].firstarc->adjvex;
    return -1;
}

int NextAdjVex(ALGraph G, int v, int w)
{
    ANode *p;
    p = G.vex[v].firstarc;
    if (v<0 || v >= G.vnum)return -1;
    if (w<0 || w >= G.vnum)return -1;
    while (p&&p->adjvex != w)
        p = p->next;
    if (p != NULL || p->next != NULL)
        return p->next->adjvex;
    return -1;
}

//DFS
int visited[MAXNUM];
void DFS(ALGraph G, int v);
void DFSTraverse(ALGraph G)
{
    printf("深度遍歷為:\n");
    int v;
    for (v = 0; v<G.vnum; v++)
        visited[v] = 0;
    for (v = 0; v<G.vnum; v++)
        if (visited[v] == 0)DFS(G, v);
    printf("\n");
}
void DFS(ALGraph G, int v)
{
    int w;
    printf("%3c", G.vex[v].data);
    visited[v] = 1;
    w = FirstAdjVex(G, v);
    while (w != -1)
    {
        if (visited[w] == 0)DFS(G, w);
        w = NextAdjVex(G, v, w);
    }

}

//BFS遍歷-鏈隊列
typedef struct QNode
{
    ElemType data;
    struct QNode *next;
}QNode, *QueuePtr;
typedef struct
{
    QueuePtr front;
    QueuePtr rear;
}LinkQueue;

Status InitQueue(LinkQueue &Q)
{
    Q.front = (QNode*)malloc(sizeof(QNode));
    if (!Q.front)return ERROR;
    Q.front->next = NULL;
    Q.rear = Q.front;
    return OK;
}
//入隊
Status EnQueue(LinkQueue &Q, ElemType e)
{
    QueuePtr p;
    p = (QNode*)malloc(sizeof(QNode));
    if (!p)return ERROR;
    p->next = NULL;
    p->data = e;
    Q.rear->next = p;
    Q.rear = p;
    return OK;
}

//出隊
Status DeQueue(LinkQueue &Q, ElemType &e)
{
    QueuePtr p;
    if (Q.rear == Q.front)
        return ERROR;
    p = Q.front->next;
    Q.front->next = p->next;
    if (Q.front->next == Q.rear)
        Q.rear = Q.front;
    e = p->data;
    free(p);//清空
    return OK;
}

//判空
bool EmptyQueue(LinkQueue Q)
{
    if (Q.front == Q.rear)return true;
    else return false;
}

//BFS
void BFS(ALGraph G)
{
    printf("廣度優先遍歷為:\n");
    int v;
    LinkQueue Q;
    InitQueue(Q);
    for (v = 0; v<G.vnum; v++)//初始化
        visited[v] = 0;
    for (v = 0; v<G.vnum; v++)
    {
        if (visited[v] == 1)continue;
        printf("%3c", G.vex[v].data);
        visited[v] = 1;
        EnQueue(Q, G.vex[v].data);
        while (EmptyQueue == 0)
        {
            int v;
            ElemType e;
            DeQueue(Q, e);
            v = Location(G, e);
            int w = FirstAdjVex(G, v);
            while (w != -1)
            {
                w = NextAdjVex(G, v, w);
                if (visited[w] = 1)continue;
                printf("%3c", G.vex[w].data);
                EnQueue(Q, G.vex[w].data);
                visited[w] = 1;
            }
        }
    }
}

int main()
{
    ALGraph G;
    ElemType v[] = "abcdef";
    ElemType a[] = "ab,ac,ad,be,ce,df";
    CreatGraph(G, 6, 6, v, a);
    DFSTraverse(G);
    BFS(G);
    getchar();
    return 0;
}
View Code

 

 

 


免責聲明!

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



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