【PTA】【C】【代码加思路】邻接矩阵存储图的深度优先遍历

本文详细介绍如何使用C++实现邻接矩阵存储的图的深度优先遍历(DFS),包括函数接口、邻接矩阵结构和示例代码,适合初学者理解图算法核心。

6-1 邻接矩阵存储图的深度优先遍历 (20 分)

试实现邻接矩阵存储图的深度优先遍历。

函数接口定义:

void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );

其中MGraph是邻接矩阵存储的图,定义如下:

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 顶点数 */
    int Ne;  /* 边数   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */

函数DFS应从第V个顶点出发递归地深度优先遍历图Graph,遍历时用裁判定义的函数Visit访问每个顶点。当访问邻接点时,要求按序号递增的顺序。题目保证V是图中的合法顶点。

裁判测试程序样例:

#include <stdio.h>

typedef enum {false, true} bool;
#define MaxVertexNum 10  /* 最大顶点数设为10 */
#define INFINITY 65535   /* ∞设为双字节无符号整数的最大值65535*/
typedef int Vertex;      /* 用顶点下标表示顶点,为整型 */
typedef int WeightType;  /* 边的权值设为整型 */

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;  /* 顶点数 */
    int Ne;  /* 边数   */
    WeightType G[MaxVertexNum][MaxVertexNum]; /* 邻接矩阵 */
};
typedef PtrToGNode MGraph; /* 以邻接矩阵存储的图类型 */
bool Visited[MaxVertexNum]; /* 顶点的访问标记 */

MGraph CreateGraph(); /* 创建图并且将Visited初始化为false;裁判实现,细节不表 */

void Visit( Vertex V )
{
    printf(" %d", V);
}

void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) );


int main()
{
    MGraph G;
    Vertex V;

    G = CreateGraph();
    scanf("%d", &V);
    printf("DFS from %d:", V);
    DFS(G, V, Visit);

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:给定图如下

5

输出样例:

DFS from 5: 5 1 3 0 2 4 6

结尾无空行

 

【思路】

         对结点编号V进行标记已遍历,并且输出Visit,再对邻接点遍历,判断邻接点和V相连,并且没有访问,然后递归,将编号改为满足相连未被访问的结点编号。

【代码】

void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) ) //二维数组头地址 结点编号 函数地址
{
    int m;
    Visited[V] = true; //已遍历标志
    Visit(V); //打印出结点
    for(m = 0; m < Graph->Nv ; m++)
    {
        if(Graph->G[V][m] ==1&&!Visited[m]) //有结点,并且未被遍历过
        {
           DFS(Graph, m, Visit); //递归调用DFS
        }
    }
    return;
}

### 邻接矩阵存储并实现深度优先遍历 #### 深度优先遍历简介 深度优先遍历(Depth First Search, DFS)是一种用于遍历或搜索树或算法。该算法会沿着一条路径尽可能深地探索节点,直到无法继续为止,随后回溯到最近的一个未完全访问的节点[^1]。 对于邻接矩阵表示的,可以通过递归或者栈的方式来实现DFS。下面分别介绍两种方式的具体实现方法以及代码示例。 --- #### 方法一:基于递归的深度优先遍历 ##### 实现思路 1. 定义一个布尔数组 `visited` 来记录每个节点是否已被访问过。 2. 对于当前节点,标记其为已访问,并将其入结果序列中。 3. 查找当前节点的所有邻居节点(通过邻接矩阵),如果某个邻居节点尚未被访问,则对该邻居节点执行递归调用。 ##### Python代码示例 ```python def dfs_recursive(graph, start_node, visited=None): if visited is None: visited = set() # 初始化已访问集合 visited.add(start_node) # 标记当前节点为已访问 print(start_node, end=" ") # 输出当前节点 n = len(graph) # 获取中的节点数 for neighbor in range(n): # 遍历所有可能的邻居节点 if graph[start_node][neighbor] != 0 and neighbor not in visited: # 如果存在边且未访问 dfs_recursive(graph, neighbor, visited) # 测试数据:邻接矩阵表示的 graph_matrix = [ [0, 1, 0, 1], [0, 0, 1, 1], [0, 1, 0, 0], [1, 0, 0, 0] ] print("Recursive DFS Traversal:") dfs_recursive(graph_matrix, 0) ``` --- #### 方法二:基于栈的深度优先遍历 ##### 实现思路 1. 创建一个栈并将起始节点压入栈中。 2. 当栈不为空时,弹出栈顶元素作为当前处理节点。 3. 若当前节点未被访问过,则标记为已访问,并将其所有未访问过的邻居节点依次压入栈中。 ##### Python代码示例 ```python def dfs_iterative(graph, start_node): stack = [start_node] # 初始化栈 visited = set([start_node]) # 记录已访问节点 while stack: current_node = stack.pop() print(current_node, end=" ") n = len(graph) # 的节点数量 neighbors = [] for i in range(n): # 找到当前节点的所有邻居 if graph[current_node][i] != 0: neighbors.append(i) # 将未访问的邻居按逆序压入栈中 for neighbor in reversed(neighbors): if neighbor not in visited: visited.add(neighbor) stack.append(neighbor) # 测试数据:邻接矩阵表示的 graph_matrix = [ [0, 1, 0, 1], [0, 0, 1, 1], [0, 1, 0, 0], [1, 0, 0, 0] ] print("\nIterative DFS Traversal:") dfs_iterative(graph_matrix, 0) ``` --- #### 关键点总结 - **时间复杂度**:无论是递归还是迭代版本,假设中有 \(V\) 个节点和 \(E\) 条边,时间复杂度均为 \(O(V^2)\),因为每次都需要检查整个邻接矩阵的一行。 - **空间复杂度**:递归版本的空间开销取决于递归深度;而迭代版本则依赖于显式的栈结构大小。 - **适用场景**:当较为稀疏时,通常推荐使用邻接表而非邻接矩阵来节省内存消耗[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码上游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值