圖的遍歷和相關操作

圖的遍歷和相關操作

參考書籍:王道--數據結構--代碼在vs2019驗證過!

             圖的創建,打印,廣度優先遍歷,深度優先遍歷


測試代碼:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <iostream>
#define MAX 100
#define isLetter(a) ((((a)>='a')&&((a)<='z')) || (((a)>='A')&&((a)<='Z')))
#define LENGTH(a) (sizeof(a)/sizeof(a[0]))

// 鄰接表中表對應的鏈表的頂點
typedef struct _ENode
{
    int ivex;                   // 該邊所指向的頂點的位置
    struct _ENode* next_edge;   // 指向下一條弧的指針
}ENode, * PENode;

// 鄰接表中表的頂點
typedef struct _VNode
{
    char data;                  // 頂點信息
    ENode* first_edge;          // 指向第一條依附該頂點的弧
}VNode;

// 鄰接表
typedef struct _LGraph
{
    int vexnum;                 // 圖的頂點的數目
    int edgnum;                 // 圖的邊的數目
    VNode vexs[MAX];
}LGraph;

/*
 * 返回ch在matrix矩陣中的位置
 */
static int get_position(LGraph g, char ch)
{
    int i;
    for (i = 0; i < g.vexnum; i++)
        if (g.vexs[i].data == ch)
            return i;
    return -1;
}

/*
 * 讀取一個輸入字符
 */
static char read_char()
{
    char ch;

    do {
        ch = getchar();
    } while (!isLetter(ch));

    return ch;
}

/*
 * 將node鏈接到list的末尾
 */
static void link_last(ENode* list, ENode* node)
{
    ENode* p = list;

    while (p->next_edge)
        p = p->next_edge;
    p->next_edge = node;
}

/*
 * 創建鄰接表對應的圖(自己輸入)
 */
LGraph* create_lgraph()
{
    char c1, c2;
    int v, e;
    int i, p1, p2;
    ENode* node1, * node2;
    LGraph* pG;

    // 輸入"頂點數"和"邊數"
    printf("input vertex number: ");
    scanf_s("%d", &v);
    printf("input edge number: ");
    scanf_s("%d", &e);
    if (v < 1 || e < 1 || (e > (v * (v - 1))))
    {
        printf("input error: invalid parameters!\n");
        return NULL;
    }

    if ((pG = (LGraph*)malloc(sizeof(LGraph))) == NULL)
        return NULL;
    memset(pG, 0, sizeof(LGraph));

    // 初始化"頂點數"和"邊數"
    pG->vexnum = v;
    pG->edgnum = e;
    // 初始化"鄰接表"的頂點
    for (i = 0; i < pG->vexnum; i++)
    {
        printf("vertex(%d): ", i);
        pG->vexs[i].data = read_char();
        pG->vexs[i].first_edge = NULL;
    }

    // 初始化"鄰接表"的邊
    for (i = 0; i < pG->edgnum; i++)
    {
        // 讀取邊的起始頂點和結束頂點
        printf("edge(%d): ", i);
        c1 = read_char();
        c2 = read_char();

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2);

        // 初始化node1
        node1 = (ENode*)calloc(1, sizeof(ENode));
        node1->ivex = p2;
        // 將node1鏈接到"p1所在鏈表的末尾"
        if (pG->vexs[p1].first_edge == NULL)
            pG->vexs[p1].first_edge = node1;
        else
            link_last(pG->vexs[p1].first_edge, node1);
        // 初始化node2
        node2 = (ENode*)calloc(1, sizeof(ENode));
        node2->ivex = p1;
        // 將node2鏈接到"p2所在鏈表的末尾"
        if (pG->vexs[p2].first_edge == NULL)
            pG->vexs[p2].first_edge = node2;
        else
            link_last(pG->vexs[p2].first_edge, node2);
    }

    return pG;
}

/*
 * 創建鄰接表對應的圖(用已提供的數據),無向圖
 */
LGraph* create_example_lgraph()
{
    char c1, c2;
    char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
    char edges[][2] = {
        {'A', 'C'},
        {'A', 'D'},
        {'A', 'F'},
        {'B', 'C'},
        {'C', 'D'},
        {'E', 'G'},
        {'F', 'G'} };
    int vlen = LENGTH(vexs);
    int elen = LENGTH(edges);
    int i, p1, p2;
    ENode* node1, * node2;
    LGraph* pG;


    if ((pG = (LGraph*)malloc(sizeof(LGraph))) == NULL)
        return NULL;
    memset(pG, 0, sizeof(LGraph));

    // 初始化"頂點數"和"邊數"
    pG->vexnum = vlen;
    pG->edgnum = elen;
    // 初始化"鄰接表"的頂點
    for (i = 0; i < pG->vexnum; i++)
    {
        pG->vexs[i].data = vexs[i];
        pG->vexs[i].first_edge = NULL;
    }

    // 初始化"鄰接表"的邊
    for (i = 0; i < pG->edgnum; i++)
    {
        // 讀取邊的起始頂點和結束頂點
        c1 = edges[i][0];
        c2 = edges[i][1];

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2);

        // 初始化node1
        node1 = (ENode*)calloc(1, sizeof(ENode));
        node1->ivex = p2;
        // 將node1鏈接到"p1所在鏈表的末尾"
        if (pG->vexs[p1].first_edge == NULL)
            pG->vexs[p1].first_edge = node1;
        else
            link_last(pG->vexs[p1].first_edge, node1);
        // 初始化node2
        node2 = (ENode*)calloc(1, sizeof(ENode));
        node2->ivex = p1;
        // 將node2鏈接到"p2所在鏈表的末尾"
        if (pG->vexs[p2].first_edge == NULL)
            pG->vexs[p2].first_edge = node2;
        else
            link_last(pG->vexs[p2].first_edge, node2);
    }

    return pG;
}

/*
 * 深度優先搜索遍歷圖的遞歸實現
 */
static void DFS(LGraph G, int i, int* visited)
{
    ENode* node;

    visited[i] = 1;
    printf("%c ", G.vexs[i].data);
    node = G.vexs[i].first_edge;
    while (node != NULL)
    {
        if (!visited[node->ivex])
            DFS(G, node->ivex, visited);
        node = node->next_edge;
    }
}

/*
 * 深度優先搜索遍歷圖
 */
void DFSTraverse(LGraph G)
{
    int i;
    int visited[MAX];       // 頂點訪問標記

    // 初始化所有頂點都沒有被訪問
    for (i = 0; i < G.vexnum; i++)
        visited[i] = 0;

    printf("DFS: ");
    //從A開始深度優先遍歷
    for (i = 0; i < G.vexnum; i++)
    {
        if (!visited[i])
            DFS(G, i, visited);
    }
    printf("\n");
}

/*
 * 廣度優先搜索(類似於樹的層次遍歷)
 */
void BFS(LGraph G)
{
    int head = 0;
    int rear = 0;
    int queue[MAX];     // 輔組隊列
    int visited[MAX];   // 頂點訪問標記
    int i, j, k;
    ENode* node;

    //每個頂點未被訪問
    for (i = 0; i < G.vexnum; i++)
        visited[i] = 0;
    //從零號頂點開始遍歷
    printf("BFS: ");
    for (i = 0; i < G.vexnum; i++)//對每個連同分量均調用一次BFS
    {
        if (!visited[i])
        {
            visited[i] = 1;
            printf("%c ", G.vexs[i].data);
            queue[rear++] = i;  // 入隊列
        }
        while (head != rear)
        {
            j = queue[head++];  // 出隊列
            node = G.vexs[j].first_edge;
            while (node != NULL)
            {
                k = node->ivex;
                if (!visited[k])
                {
                    visited[k] = 1;
                    printf("%c ", G.vexs[k].data);
                    queue[rear++] = k;
                }
                node = node->next_edge;
            }
        }
    }
    printf("\n");
}

/*
 * 打印鄰接表圖
 */
void print_lgraph(LGraph G)
{
    int i;
    ENode* node;

    printf("List Graph:\n");
    for (i = 0; i < G.vexnum; i++)
    {
        printf("%d(%c): ", i, G.vexs[i].data);
        node = G.vexs[i].first_edge;
        while (node != NULL)
        {
            printf("%d(%c) ", node->ivex, G.vexs[node->ivex].data);
            node = node->next_edge;
        }
        printf("\n");
    }
}
/*
 * 創建鄰接表對應的圖(有向圖)
 */
LGraph* create_example_lgraph_directed()
{
    char c1, c2;
    char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
    char edges[][2] = {
        {'A', 'B'},
        {'B', 'C'},
        {'B', 'E'},
        {'B', 'F'},
        {'C', 'E'},
        {'D', 'C'},
        {'E', 'B'},
        {'E', 'D'},
        {'F', 'G'} };
    int vlen = LENGTH(vexs);
    int elen = LENGTH(edges);
    int i, p1, p2;
    ENode* node1;
    LGraph* pG;


    if ((pG = (LGraph*)malloc(sizeof(LGraph))) == NULL)
        return NULL;
    memset(pG, 0, sizeof(LGraph));

    // 初始化"頂點數"和"邊數"
    pG->vexnum = vlen;
    pG->edgnum = elen;
    // 初始化"鄰接表"的頂點
    for (i = 0; i < pG->vexnum; i++)
    {
        pG->vexs[i].data = vexs[i];
        pG->vexs[i].first_edge = NULL;
    }

    // 初始化"鄰接表"的邊
    for (i = 0; i < pG->edgnum; i++)
    {
        // 讀取邊的起始頂點和結束頂點
        c1 = edges[i][0];
        c2 = edges[i][1];

        p1 = get_position(*pG, c1);
        p2 = get_position(*pG, c2);
        // 初始化node1
        node1 = (ENode*)calloc(1, sizeof(ENode));
        node1->ivex = p2;
        // 將node1鏈接到"p1所在鏈表的末尾"
        if (pG->vexs[p1].first_edge == NULL)
            pG->vexs[p1].first_edge = node1;
        else
            link_last(pG->vexs[p1].first_edge, node1);
    }

    return pG;
}

//圖的創建,打印,廣度優先遍歷,深度優先遍歷
//講 有向圖
int main()
{
    LGraph* pG;

    // 無向圖自定義"圖"(自己輸入數據)
    //pG = create_lgraph();
    // 無向圖的創建,採用已有的"圖"
    //pG = create_example_lgraph();
        //有向圖的創建
    pG = create_example_lgraph_directed();
    // 打印圖
    print_lgraph(*pG);
    BFS(*pG);
    DFSTraverse(*pG);
    system("pause");
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章