图的 DFS (深度优先搜索)

代码:

void Visit(Vertex V)
{
    printf("正在访问顶点%d\n", V);
}


// Visited[] 为全局变量, 已经初始化为 false
// 以 V 为出发点对邻接表存储的图 Graph 进行 DFS 搜索
void DFS(LGraph Graph, Vertex V, void(*Visit)(Vertex))
{
    PtrToAdjVNode W;

    Visit(V); // 访问第 V 个顶点
    Visited[V] = 1; // 标记 V 已访问

    for (W = Graph->G[V].FirstEdge; W; W = W->Next) // 对 V 的每个邻接点 W->AdjV
        if (!Visited[W->AdjV]) // 若 W->AdjV 为被访问
            DFS(Graph, W->AdjV, Visit); // 则递归访问之
}

配套教程 --> 浙江大学陈越数据结构图部分, 教材 --> 《数据结构第二版》(陈越)

完整代码(这里的图用的是邻接表的实现):

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

#define MaxVertexNum 100 // 最大顶点数设为 100
typedef int Vertex; // 用顶点下标表示顶点, 为整型
typedef int WeightType; // 边的权值为整型
typedef char DataType; // 顶点存储的数据类型为字符型

// 全局变量 Visited[], 初始化为 false
char Visited[MaxVertexNum]; // 0 代表 false, 1 代表 true

static void init()
{
    memset(Visited, 0, MaxVertexNum);
}

// 边的定义
typedef struct ENode *PtrToENode;
struct ENode
{
    Vertex V1, V2; // 有向边 <V1, V2>
    WeightType Weight; // 权重
};

typedef PtrToENode Edge;

// 邻接点的定义
typedef struct AdjVNode *PtrToAdjVNode; // Adjacency list --> 邻接表
struct AdjVNode
{
    Vertex AdjV; // 邻接点下标
    WeightType Weight; // 边权重
    PtrToAdjVNode Next; // 指向下一个邻接点的指针
};

// 顶点表头节点的定义
typedef struct VNode
{
    PtrToAdjVNode FirstEdge; // 边表头指针
    DataType Data; // 存顶点的数据
    // 注意, 很多情况下, 顶点无数据, 此时 Data 可以不用出现
} AdjList[MaxVertexNum]; // AdjList 是邻接表类型

// 图节点的定义
typedef struct GNode *PtrToGNode;
struct GNode
{
    int Nv; // 顶点数
    int Ne; // 边数
    AdjList G; // 邻接表, 用数组方式存储每一个顶点的表头节点
};
typedef PtrToGNode LGraph; // 以邻接表的方式存储的图类型

// 初始化一个有 VertexNum 个顶点但没有边的图
LGraph CreateGraph(int VertexNum)
{
    Vertex V;
    LGraph Graph;

    Graph = (LGraph) malloc(sizeof(struct GNode)); // 建立图
    Graph->Nv = VertexNum; // 顶点数为 VertexNum
    Graph->Ne = 0; // 边数为 0
    // 初始化邻接表头指针
    // 注意: 这里默认顶点编号从 0 开始, 到(Graph->Nv - 1)
    for (V = 0; V < Graph->Nv; V++)
        Graph->G[V].FirstEdge = NULL;

    return Graph;
}

// 插入边
void InsertEdge(LGraph Graph, Edge E)
{
    PtrToAdjVNode NewNode;
    // 插入边 <V1, V2>
    // 为 V2 建立新的邻接点
    NewNode = (PtrToAdjVNode) malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V2;
    NewNode->Weight = E->Weight;
    // 将 V2 插入 V1 的表头(插入表头比插入表尾明显容易实现)
    NewNode->Next = Graph->G[E->V1].FirstEdge;
    Graph->G[E->V1].FirstEdge = NewNode;

    // 若是无向图, 还有插入边 <V2, V1>
    // 为 V1 建立新的邻接点
    /*NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V1;
    NewNode->Weight = E->Weight;
    // 将 V1 插入 V2 的表头
    NewNode->Next = Graph->G[E->V2].FirstEdge;
    Graph->G[E->V2].FirstEdge = NewNode;*/
}

// 建图
LGraph BuildGraph()
{
    LGraph Graph;
    Edge E;
    // Vertex V;
    int Nv, i;

    scanf("%d", &Nv); // 读入顶点个数
    Graph = CreateGraph(Nv); // 初始化有 Nv 个顶点但没有边的图

    scanf("%d", &(Graph->Ne)); // 读入边数
    if (Graph->Ne != 0)
    { // 如果有边
        E = (Edge) malloc(sizeof(struct ENode));
        // 读入边, 格式为 "起点, 终点, 权重", 插入邻接表
        for (i = 0; i < Graph->Ne; i++)
        {
            scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
            // 注意: 如果权重不是整型, Weight 的读入格式要改
            InsertEdge(Graph, E);
        }
    }

    // 如果顶点有数据的话, 读入数据
    /*for (V = 0; V < Graph->Nv; V++)
    {
        scanf("%c", &(Graph->G[V].Data));
    }*/

    return Graph;
}

// 简单遍历图
void PrintGraph(LGraph Graph)
{
    if (!Graph->G[0].FirstEdge) // 邻接表为空
        return;

    int i;
    for (i = 0; i < Graph->Nv; i++)
    {
        printf("%d: | ", i);

        PtrToAdjVNode tmp = Graph->G[i].FirstEdge;

        while (tmp)
        {
            printf("%d %d | ", tmp->AdjV, tmp->Weight);
            tmp = tmp->Next;
        }
        printf("\n");
    }
}
void Visit(Vertex V)
{
    printf("正在访问顶点%d\n", V);
}


// Visited[] 为全局变量, 已经初始化为 false
// 以 V 为出发点对邻接表存储的图 Graph 进行 DFS 搜索
void DFS(LGraph Graph, Vertex V, void(*Visit)(Vertex))
{
    PtrToAdjVNode W;

    Visit(V); // 访问第 V 个顶点
    Visited[V] = 1; // 标记 V 已访问

    for (W = Graph->G[V].FirstEdge; W; W = W->Next) // 对 V 的每个邻接点 W->AdjV
        if (!Visited[W->AdjV]) // 若 W->AdjV 为被访问
            DFS(Graph, W->AdjV, Visit); // 则递归访问之
}


// 测试一组数据, 测试的图有 5 个顶点, 8 条有向边
// <1, 0, 9> <0, 2, 6> <2, 4, 7> <4, 3, 6>
// <3, 1, 5> <1, 2, 4> <0, 3, 3> <3, 4, 8>
int main()
{
    /*---------- 初始测试 ----------*/
    // LGraph Graph = BuildGraph();
    // PrintGraph(Graph);
    /*---------- 初始测试 ----------*/

    /*---------- 测试 DFS ----------*/
    init();
    LGraph Graph = BuildGraph();
    DFS(Graph, 0, Visit);


    /*---------- 测试 DFS ----------*/

    return 0;
}

// 测试数据
/*
5
8
1 0 9
0 2 6
2 4 7
4 3 6
3 1 5
1 2 4
0 3 3
3 4 8
*/

输出结果:

20201120005549

按: 测试用的图的示意 -->

20201120005929

posted @ 2020-11-20 01:00  模糊计算士  阅读(697)  评论(0编辑  收藏  举报