【数据结构学习记录20】——图的两种遍历

一.两种遍历

1.深度优先搜索(DFS)

深度优先搜索,顾名思义,就是优先向更深的地方搜索。假设这是一棵树,那么深度优先搜索会优先向深度更高的结点搜索。因为深度优先搜索的概念,要到最深的结点后才返回,所以同层次的结点是先访问,后遍历,符合栈的结构模型,所以我们的深度优先搜索一般都是通过递归实现。
对于这个像树的图来讲:
在这里插入图片描述
假设我们的从1开始遍历,那么他会优先访问深度更高的顶点:
在这里插入图片描述
最终,它的遍历顺序为:
GraphG DFS:1 2 4 8 5 3 6 7

2.广度优先搜索(BFS)

定义与DFS相似,广度优先搜索是优先将同一层次的结点搜索完成后,再向下一个深度的结点搜索。又用树来举例子:假设对一棵树进行广度优先搜索,那么它会首先先将自己的兄弟结点遍历完后,才会向更深的儿子结点进行遍历。所以,同一结点的儿子们是先访问的先遍历,所以很符合队列的模型,所以我们一般通过队列实现。
还是对于这个图
在这里插入图片描述
我们广度优先搜索的过程为:
在这里插入图片描述
结果是:
GraphG BFS:1 2 3 4 5 6 7 8

3.两者的差别

用两张图直观的表示这两种搜索,比如A方块是在迷宫里,我们要遍历它到终点的路。
深度优先搜索:
在这里插入图片描述

广度优先搜索:

在这里插入图片描述

二.代码实现

看看效果:
在这里插入图片描述

因为图个各种构造,所以我们采用有向图+邻接表的方法来实现。
先构造顶点,再构造弧。

#include <stdio.h>
#include <stdlib.h>

#define         OK          1
#define         ERROR       0
#define         MaxLen      100

typedef struct ArcNode{
    
    
    int Head;
    struct ArcNode *nextArc;
}ArcNode;   // 创建弧结点

typedef struct VNode{
    
    
    char NodeName;
    ArcNode *nextArc;
}VNode;     // 创建Vertex顶点结点

typedef struct Graph{
    
    
    int len;
    VNode *Nbase;   // 线性存储顶点结点
}Graph;     // 创建一张图

int MarkGraph[MaxLen];  // 标记数组

Graph *GraphCreat(void);
int GraphShowList(Graph *G);
int GraphDFS(Graph *G);
int DFS(Graph *G, int vertex);
int GraphBFS(Graph *G);

int main()
{
    
    
    Graph *map = GraphCreat();
    GraphShowList(map);
    GraphDFS(map);
    GraphBFS(map);
    return 0;
}

Graph *GraphCreat(void)
{
    
    
    Graph *G = (Graph*)malloc(sizeof(Graph));
    int lenV, lenA;
    int i, tail, head;
    char temp;
    ArcNode *ArcNow, *ArcLast;

    printf("please input the number of Vertex and Arc:");
    scanf("%d %d", &lenV, &lenA);   // 获取 顶点数和弧的个数

    if (lenV > MaxLen)
    {
    
    
        printf("Over MaxLenth");
        exit(ERROR);
    }   // 限制下大小

    // 创建顶点线性表
    G->len = lenV;
    G->Nbase = (VNode*)malloc(sizeof(VNode)*lenV);
    
    // 存顶点名字
    printf("please input Vertexs' name:\n");
    rewind(stdin);
    for (i = 0; i < lenV; ++i)
    {
    
    
        scanf("%c", &temp);
        (G->Nbase+i)->NodeName = temp;
        (G->Nbase+i)->nextArc = NULL;
    }
    // 存弧
    printf("please input (tail,head) as the arc:\n");
    for (i = 0; i < lenA; ++i)
    {
    
    
        rewind(stdin);
        scanf("%d %d", &tail, &head);
        
        // 如果是顶点的第一个弧
        if ((G->Nbase+tail)->nextArc == NULL)
        {
    
    
            (G->Nbase+tail)->nextArc = (ArcNode*)malloc(sizeof(ArcNode));
            (G->Nbase+tail)->nextArc->Head = head;
            (G->Nbase+tail)->nextArc->nextArc = NULL;
        }
        else // 非顶点的第一个弧
        {
    
    
            ArcNow = (G->Nbase+tail)->nextArc;
            while(ArcNow->nextArc != NULL)  // 循环移动到最后一个弧
            {
    
    
                ArcNow = ArcNow->nextArc;
            }
            // 创建弧结点
            ArcNow->nextArc = (ArcNode*)malloc(sizeof(ArcNode));
            ArcNow->nextArc->Head = head;
            ArcNow->nextArc->nextArc = NULL;
        }
    }

    return G;
}

int GraphShowList(Graph *G) // 循环输出每个顶点的弧信息
{
    
    
    int i;
    ArcNode *ArcNow;

    printf("\n");
    for (i = 0; i < G->len; ++i)    // 循环
    {
    
    
        printf("%d: %c", i, (G->Nbase+i)->NodeName); // 输出顶点名
        ArcNow = (G->Nbase+i)->nextArc;
        while(ArcNow != NULL)   // 循环输出每个弧
        {
    
    
            printf("->%c", (G->Nbase+ArcNow->Head)->NodeName);
            ArcNow = ArcNow->nextArc;
        }
        printf("\n");
    }
}

int GraphDFS(Graph *G)  // DFS初始化
{
    
    
    int i = 0;
    for (i = 0; i < G->len; ++i)    // 更新结点标记数组
    {
    
    
        MarkGraph[i] = 0;
    }
    printf("\nGraphG DFS:");
    DFS(G, 0);  // 开始DFS
    
}

int DFS(Graph *G, int vertex)
{
    
    
    ArcNode *ArcNow;
    if (MarkGraph[vertex] == 0) // 如果该顶点未被访问过
    {
    
    
        printf("%c ", (G->Nbase+vertex)->NodeName); // 输出该顶点
        MarkGraph[vertex] = 1;  // 标记该顶点被访问过
        ArcNow = (G->Nbase+vertex)->nextArc;    // 下一条弧
        while(ArcNow != NULL)   // 循环递归该顶点的所有弧
        {
    
    
            DFS(G, ArcNow->Head);   
            ArcNow = ArcNow->nextArc;
        }
    }
}

int GraphBFS(Graph *G)  // BFS
{
    
    
    int *Queue = (int*)malloc(sizeof(int) * G->len * G->len);   // 创建一个模拟队列
    int QFront, QTail, vertex, i;   // 队列顶指针 队列尾
    ArcNode *ArcNow;

    Queue[0] = 0; // 把0号顶点压入队列
    QFront = 0;
    QTail = 1;
    for (i = 0; i < G->len; ++i)    // 初始化标记数组
    {
    
    
        MarkGraph[i] = 0;
    }
    printf("\nGraphG BFS:");

    while(QFront < QTail)   // 队尾队头相等,则队列空
    {
    
    
        vertex = Queue[QFront]; // 队头出队
        QFront += 1;
        if (MarkGraph[vertex] == 0) // 类似于DFS了
        {
    
    
            printf("%c ", (G->Nbase+vertex)->NodeName); // 输出当前顶点信息
            MarkGraph[vertex] = 1;  // 标记当前顶点已用
            ArcNow = (G->Nbase+vertex)->nextArc;    // 开始循环
            while(ArcNow != NULL)   // 非空
            {
    
    
                Queue[QTail] = ArcNow->Head;    // 入队
                QTail += 1;
                ArcNow = ArcNow->nextArc;   // 迭代
            }
        }
    }
    printf("\n");
}

猜你喜欢

转载自blog.csdn.net/u011017694/article/details/110621552