C/C++语言:图的遍历之深度优先搜索 代码实现

深度优先搜索(Depth First Search,DFS)

PS:图的深度优先搜索DFS,代码实现有多种,这里:

1、图的存储:邻接矩阵

2、辅助工具: 栈stack,栈中装的是 顶点对象

              访问标志数组visited,int 型

一、图

无向图G 及其邻接矩阵表示

在这里插入图片描述

二、实现

1、从 a 开始访问,DFS 顺序该为:a b d h e c f g

2、思路:

  • 说明:1)每个顶点都是先访问之后,再入栈 ;
          2)栈为空时搜索结束!
  • 第一步:假如某一时刻栈顶元素是 v:查看与栈顶元素 v 是否有相邻的且还没有被访问过的顶点 w。
  • 第二步:若有,先访问w后,再将顶点w入栈。则新的栈顶元素为 w,再重复第一步(判断与新的栈顶元素 w是否有相邻的且还没有被访问过的顶点)
  • 第三步:若没有,将栈顶元素 v 出栈。如果栈顶元素 v 出栈后,栈非空且新的栈顶元素为s,再重复第一步(判断与新的栈顶元素 s是否有相邻的且还没有被访问过的顶点);如果栈顶元素 v出栈后,栈为空,则搜索结束!

3、(傻瓜式)分析

1)先访问a,再将a压栈,栈顶元素为a;
2)查看与栈顶元素a是否有相邻的且还有没访问过的顶点,有顶点b,访问顶点b并压栈,新的栈顶元素为b
3)查看与栈顶元素b是否有相邻的且还有没访问过的顶点,有顶点d,访问顶点d并压栈,新的栈顶元素为d
4)查看与栈顶元素d是否有相邻的且还有没访问过的顶点,有顶点h,访问顶点h并压栈,新的栈顶元素为h
5) 查看与栈顶元素h是否有相邻的且还有没访问过的顶点,有顶点e,访问顶点e并压栈,新的栈顶元素为e
6) 查看与栈顶元素e是否有相邻的且还有没访问过的顶点,没有。将栈顶元素e出栈(回溯),栈非空且新的栈顶元素为h
7)查看与栈顶元素h是否有相邻的且还有没访问过的顶点,没有。将栈顶元素h出栈(回溯),栈非空且新的栈顶元素为d
8)查看与栈顶元素d是否有相邻的且还有没访问过的顶点,没有。将栈顶元素d出栈(回溯),栈非空且新的栈顶元素为b
9)查看与栈顶元素b是否有相邻的且还有没访问过的顶点,没有。将栈顶元素b出栈(回溯),栈非空且新的栈顶元素为a
10)查看与栈顶元素a是否有相邻的且还有没访问过的顶点,有顶点c,访问顶点c并压栈,新的栈顶元素为c
11)查看与栈顶元素c是否有相邻的且还有没访问过的顶点,有顶点f,访问顶点f并压栈,新的栈顶元素为f
12)查看与栈顶元素f是否有相邻的且还有没访问过的顶点,有顶点g,访问顶点g并压栈,新的栈顶元素为g
13)查看与栈顶元素g是否有相邻的且还有没访问过的顶点,没有。将栈顶元素g出栈(回溯),栈非空且新的栈顶元素为f
14)查看与栈顶元素f是否有相邻的且还有没访问过的顶点,没有。将栈顶元素f出栈(回溯),栈非空且新的栈顶元素为c
15)查看与栈顶元素c是否有相邻的且还有没访问过的顶点,没有。将栈顶元素c出栈(回溯),栈非空且新的栈顶元素为a
16)查看与栈顶元素a是否有相邻的且还有没访问过的顶点,没有。将栈顶元素a出栈(回溯),栈为空,则搜索结束

4、代码

头文件:home10.h
#include<iostream>
#include "stack"
using namespace std;

#define MVNum 100      //图的顶点个数,最大值Max_Vertex_Num

typedef char VertexType;    //顶点类型,char
typedef int ArcType;    //权值类型,int

int visited[MVNum]={0}; //访问标志数组,初值全为0,表示所有顶点都没有被访问过
stack<VertexType>Stack;//栈


typedef struct {
    VertexType vertexs[MVNum];   //顶点数组,从0开始存
    ArcType arcs[MVNum][MVNum]; //邻接矩阵,从arcs[0][0]开始存
    int vernum,arcnum;  //图当前的顶点个数、边个数
}AMGraph;//图的邻接矩阵

/*
 * TODO:查找与顶点v相邻的且是没有被访问过的顶点w
 * 若有就返回w,没有就返回NULL
 * */
VertexType haveAdjacency(AMGraph G, VertexType v){
    //找出v顶点对应的数组下标i
    int i = 0;
    while (v != G.vertexs[i]) {
        i++;
    }
    //扫描邻接矩阵G.arcs中下标为i的一维数组,查找与顶点v相邻的且是没有被访问过的顶点w
    int j = 0;
    while((G.arcs[i][j] != 1 || visited[j] != 0) && j < G.vernum){
        //循环结束条件:(G.arcs[i][j] == 1 && visited[j] == 0)即找到与v相邻的,结束 或者 根本就没有与v相邻的,也结束
        j++;
    }
    if(j < G.vernum){//有这样一个顶点w,返回w
        VertexType w = G.vertexs[j];
        return w;
    }
    else if(j >= G.vernum)//没有,返回NULL
        return NULL;
}

/*
 * TODO:顶点v访问过之后,相应地在visited数组中把它置1
 * */
void setVisited(AMGraph G, VertexType v){
    int i = 0;
    while (v != G.vertexs[i]) {//查找顶点v对应的数组下标
        i++;
    }
    visited[i] = 1;
}

/*
 * TODO:
 * 注意:顶点都是先被访问,然后再入栈;
 * v是栈顶元素,每次都是判断与栈顶元素v是否有相邻的且是没有被访问过的顶点w:
 * 有,那么就访问顶点w并入栈,然后再递归判断与新的栈顶元素w是否有相邻的且未被访问过的顶点,
 * 没有,那么栈顶元素出栈,然后再递归判断与新的栈顶元素r是否有相邻的且未被访问过的顶点.
 * */
void DFS(AMGraph G, VertexType v){
            //查看是否有,与栈顶v相邻的且还没有被访问过的顶点w,有就返回顶点w,没有就返回NULL
            VertexType w = haveAdjacency(G,v);
            if(w){//有
                cout << w << " ";//访问
                setVisited(G,w);//w访问之后,相应地在visited数组中把它置1
                Stack.push(w);
                //递归
                DFS(G,w);
//            return;
            }
            else{//没有,这个时候栈一定是非空的
                Stack.pop();//pop:仅删除栈顶元素,但不返回
                //
                if(Stack.empty())//取出栈顶后,栈空,搜索结束
                    return;
                else{//取出栈顶后,栈非空,继续判断
                    VertexType w = Stack.top();//top:仅返回栈顶元素,但不删除
                    DFS(G,w);
//                return;
                }
            }
}

/*
 * TODO:从图中的顶点v开始深度优先搜索
 * */
void Function(AMGraph G, VertexType v){
    cout << v << " ";//访问
    setVisited(G,v);//访问之后,给visited数组置1
    Stack.push(v);
    DFS(G,v);
}

测试函数:home10_main.cpp
//
// Created by dong on 2022-03-16.
//
#include "home10.h"

int main(){
   AMGraph G;
   G.vernum = 8;//8个顶点
   G.arcnum = 9;
   //
   char test[8]={'a','b','c','d','e','f','g','h'};
   for(int i = 0; i < 8; i++)
       G.vertexs[i] = test[i];
   //
   int a[8][8]={0,1,1,0,0,0,0,0,
                1,0,0,1,1,0,0,0,
                1,0,0,0,0,1,1,0,
                0,1,0,0,0,0,0,1,
                0,1,0,0,0,0,0,1,
                0,0,1,0,0,0,1,0,
                0,0,1,0,0,1,0,0,
                0,0,0,1,1,0,0,0};
   for(int i = 0; i < 8; i++)
       for(int j = 0; j < 8; j++)
           G.arcs[i][j] = a[i][j];
   //
    Function(G,'a');

    return 0;
}

结果

在这里插入图片描述

5、最后

当然了,这个代码还有很多可以优化的,比如栈中存顶点的下标而不是整个顶点,可以去试试!

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 深度优先遍历算法是一种遍历算法,它沿着形的深度遍历形,尽可能深的搜索形的分支。 在 C 语言中,可以使用递归函数来实现深度优先遍历算法。 下面是一个简单的例子,展示了如何使用递归函数来实现深度优先遍历: ``` void dfs(int node) { // 访问当前结点 printf("%d ", node); // 遍历当前结点的所有邻居 for (int i = 0; i < num_neighbors(node); i++) { int neighbor = get_neighbor(node, i); // 递归遍历邻居 dfs(neighbor); } } ``` 在这个例子中,`dfs` 函数接收一个结点编号作为参数,然后访问这个结点,并遍历它的所有邻居。对于每个邻居,它会递归调用自身,以便对这个邻居进行深度优先遍历。 希望这个例子能对你有帮助。 ### 回答2: 深度优先遍历(Depth-First Search,DFS)是一种常用的搜索算法,用于遍历或搜索或树的所有节点。下面是实现深度优先遍历算法的伪代码: 1. 创建一个空的栈,并将起始节点入栈。 2. 创建一个空的集合,用于存储已访问的节点。 3. 当栈非空时,执行以下步骤: 1. 弹出栈顶节点,并将其标记为已访问。 2. 访问该节点。 3. 将该节点的所有未访问的邻居节点入栈(根据具体问题的要求确定入栈次序)。 4. 将该节点加入已访问的集合。 4. 结束。 下面是一个简单的实例来说明深度优先遍历的过程: 假设有如下的邻接矩阵表示的: ``` 0 1 2 3 4 0 0 1 1 0 0 1 1 0 0 1 1 2 1 0 0 0 0 3 0 1 0 0 0 4 0 1 0 0 0 ``` 从节点0开始进行深度优先遍历,按照伪代码的步骤进行操作: 1. 创建一个空的栈,并将节点0入栈。 2. 创建一个空的集合,用于存储已访问的节点。 3. 栈中弹出节点0,将其标记为已访问,并访问该节点。将节点0的邻居节点1和2入栈。 4. 栈中弹出节点2,将其标记为已访问,并访问该节点。由于节点2没有未访问的邻居,直接跳到步骤3。 5. 栈中弹出节点1,将其标记为已访问,并访问该节点。将节点1的邻居节点0入栈(节点0已访问过,不再入栈)。 6. 栈中弹出节点0,由于节点0已访问过,跳过。 7. 栈为空,结束遍历。 按照以上步骤,深度优先遍历的访问顺序为:0 -> 2 -> 1。 ### 回答3: 深度优先遍历(Depth-First Search,DFS)是一种用于或树的遍历算法。它按照深度的方向遍历的节点,一直沿着路径走到底,直到无法继续才返回上一级节点,并继续选择其他未遍历过的路径。使用递归实现深度优先遍历算法如下: 1. 首先,创建一个访问列表visited,用于记录已经访问过的节点。 2. 定义递归函数dfs,传入当前节点node作为参数: 2.1 将当前节点标记为已访问,将其加入visited列表。 2.2 遍历当前节点的邻居节点neighbors: 2.2.1 如果邻居节点未被访问过,则递归调用dfs函数,传入邻居节点作为参数。 3. 在主函数中,调用dfs函数,传入起始节点作为参数,开始深度优先遍历。 以下是具体实现代码: ```python class Node: def __init__(self, val): self.val = val self.neighbors = [] def dfs(node, visited): visited.add(node) print(node.val) for neighbor in node.neighbors: if neighbor not in visited: dfs(neighbor, visited) # 主函数 def depth_first_search(start_node): visited = set() dfs(start_node, visited) # 创建的节点 node1 = Node(1) node2 = Node(2) node3 = Node(3) node4 = Node(4) node5 = Node(5) # 构建节点之间的关系 node1.neighbors = [node2, node3] node2.neighbors = [node1, node4, node5] node3.neighbors = [node1] node4.neighbors = [node2] node5.neighbors = [node2] # 从起始节点1开始深度优先遍历 depth_first_search(node1) ``` 以上代码实现了从起始节点1开始的深度优先遍历。在遍历过程中,输出了每个节点的值,你可以看到节点的遍历顺序是1 -> 2 -> 4 -> 5 -> 3。深度优先遍历算法的时间复杂度为O(V+E),其中V为节点数目,E为边的数目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值