数据结构与算法之深度优先遍历

深度优先遍历(Depth First Search,DFS)是一种常用的图遍历算法,主要应用在查找和遍历树或图的路径问题上。

深度优先遍历的原理是从一个节点开始,尽可能深地搜索这个节点的子节点,直到到达不能再深入的节点,然后回溯到上一个节点,继续搜索它的下一个子节点,直到所有节点都被访问为止。

具体实现时,可以使用递归或者栈来遍历节点。以递归实现为例,可以定义一个递归函数,输入参数为当前节点和访问状态的数组,函数的实现如下:

  1. 先标记当前节点已经被访问过
  2. 遍历当前节点的所有未被访问过的邻居节点,对每个未访问过的邻居节点,调用递归函数访问它
  3. 返回到上一个节点,继续访问它的其他邻居节点

由于深度优先遍历是通过递归或者栈实现的,因此在访问图或树时,可能会遇到循环引用的情况,需要在实现时做好判重处理,防止出现死循环等问题。

深度优先遍历的时间复杂度为O(n+m),其中n为节点数,m为边数,因为需要遍历所有节点和边。

在这里插入图片描述

一、C 实现 深度优先遍历 及代码详解

深度优先遍历(Depth First Search, DFS)是图论中的经典算法,用于遍历或搜索树或图的所有节点。

以下是 C 语言实现深度优先遍历算法的代码详解。

代码实现:

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

#define MAX_VERTEX_NUM 20//定义最大顶点数

typedef struct ArcNode//定义弧度节点
{
    int adjvex;//邻接点下标
    struct ArcNode *nextarc;//指向下一个弧度节点的指针
}ArcNode;

typedef struct VNode//定义顶点节点
{
    int data;//顶点数据
    ArcNode *firstarc;//指向第一条弧度节点
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct Graph//定义图结构体
{
    AdjList vertices;//邻接表
    int vexnum,arcnum;//顶点数及弧度数
}Graph;

int visited[MAX_VERTEX_NUM];//标记各顶点是否被访问过

//创建一个图
void createGraph(Graph *G)
{
    int i,j,k;
    ArcNode *p;
    printf("输入顶点数和弧度数:\n");
    scanf("%d%d",&G->vexnum,&G->arcnum);
    printf("输入顶点信息:\n");
    for(i=0;i<G->vexnum;i++)
    {
        scanf("%d",&G->vertices[i].data);
        G->vertices[i].firstarc = NULL;//初始化每个顶点的指向第一条弧度节点的指针
    }
    printf("输入弧度信息:\n");
    for(k=0;k<G->arcnum;k++)
    {
        printf("输入弧度的起点和终点:\n");
        scanf("%d%d",&i,&j);
        //新建一个弧度节点,指向顶点j
        p = (ArcNode *)malloc(sizeof(ArcNode));
        p->adjvex=j;
        p->nextarc=G->vertices[i].firstarc;
        G->vertices[i].firstarc=p;
        //新建一个弧度节点,指向顶点i
        p = (ArcNode *)malloc(sizeof(ArcNode));
        p->adjvex=i;
        p->nextarc=G->vertices[j].firstarc;
        G->vertices[j].firstarc=p;
    }
}

//深度优先遍历
void DFS(Graph G,int v)
{
    ArcNode *p;
    visited[v]=1;//标记当前顶点为已访问状态
    printf("%d ",G.vertices[v].data);//输出当前访问的顶点
    p=G.vertices[v].firstarc;
    while(p!=NULL)//对当前节点的所有邻接点进行遍历
    {
        if(!visited[p->adjvex])//如果该邻接点未被访问,则对该节点进行深度优先遍历
        {
            DFS(G,p->adjvex);
        }
        p=p->nextarc;//指向下一个邻接点
    }
}

int main()
{
    Graph G;
    int i;
    createGraph(&G);
    printf("深度优先遍历的结果为:\n");
    for(i=0;i<G.vexnum;i++)
    {
        visited[i]=0;//初始化每个顶点的未访问状态
    }
    DFS(G,0);//从第0个节点开始深度优先遍历
    return 0;
}

代码详解:

在实现深度优先遍历的代码中,我们使用了一个邻接表来存储图。在邻接表中,每个顶点的指向第一条弧度节点的指针指向该顶点的第一条邻接边。另外,我们使用了一个visited数组来标记每个顶点是否被访问过,其中visited[i]为1表示第i个顶点已被访问过,为0则表示未被访问。

在createGraph函数中,我们输入了图的顶点数及弧度数,并且分别输入了每个顶点的信息。在输入每条弧度的起点和终点时,我们新建了两条弧度,一条从顶点i指向j,另一条从顶点j指向i,这两条弧度的存在是为了处理无向图。

在DFS函数中,我们先将当前节点标记为已访问状态,并输出当前访问的顶点。然后,我们遍历该节点的所有邻接点,并判断是否已经被访问过,如果没有,则以该节点为起点进行深度优先遍历。

在main函数中,我们调用了createGraph函数创建了一个图,并对visited数组进行了初始化。然后,我们从顶点0开始对整个图进行深度优先遍历。

在这里插入图片描述

二、C++ 实现 深度优先遍历 及代码详解

深度优先遍历(Depth First Search,DFS)是一种遍历图或树的算法。其核心思想是从某个结点开始,首先访问它本身,然后递归地访问其相邻结点中未曾访问过的结点,直到所有相邻结点都被访问过为止。具体实现过程可以使用递归或者栈来实现。

下面是C++实现深度优先遍历(DFS)的代码:

#include <iostream>
#include <vector>

using namespace std;

const int MAX = 100;

// 存储图的邻接表
vector<int> adj[MAX];

// 标记图中是否已经被访问
bool visited[MAX];

// 深度优先遍历算法实现
void dfs(int u) {
    visited[u] = true;
    cout << u << " ";

    for (int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        if (!visited[v]) {
            dfs(v);
        }
    }
}

int main() {
    // 构建无向图
    adj[1].push_back(2);
    adj[1].push_back(3);
    adj[2].push_back(1);
    adj[2].push_back(4);
    adj[2].push_back(5);
    adj[3].push_back(1);
    adj[3].push_back(5);
    adj[4].push_back(2);
    adj[4].push_back(5);
    adj[5].push_back(2);
    adj[5].push_back(3);
    adj[5].push_back(4);

    // 从结点1开始进行深度优先遍历
    dfs(1);

    return 0;
}

代码思路:首先定义了一个邻接表 adj 来存储图,每个元素是一个 vector<int> 类型的向量,用于存储和该结点相邻的结点。同时还定义了一个 bool 类型的数组 visited,用于标记该结点是否已经被访问过。

dfs 函数中,首先将当前结点 u 标记为已经被访问过,并输出该结点的值。然后遍历与该结点相邻的所有结点,如果其相邻结点 v 没有被访问过,则递归调用 dfs 函数继续访问。最后,当所有相邻结点都被访问完毕后,退出递归。最后,在 main 函数中,以结点1作为起始结点,调用 dfs 函数进行深度优先遍历。

这段代码可以输出以下结果:

1 2 4 5 3

表示从起始结点1开始,先访问结点1,再访问与结点1相邻的结点2和结点3,然后递归访问与结点2相邻的结点4和结点5,最后再访问与结点3相邻的结点5,遍历结束。

在这里插入图片描述

三、Java 实现 深度优先遍历 及代码详解

深度优先遍历(Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。它从根节点开始,访问尽可能深的节点,直到找到目标或到达叶节点。然后,算法回溯到前一个节点,并继续遍历未访问的节点。

以下是 Java 代码实现深度优先遍历的基本框架:

// 定义节点类
class Node {
    int val;
    List<Node> neighbors;

    public Node(int val) {
        this.val = val;
        neighbors = new ArrayList<Node>();
    }
}

// 深度优先遍历
public void dfs(Node node, boolean[] visited) {
    visited[node.val] = true;
    System.out.print(node.val + " ");

    for (Node neighbor : node.neighbors) {
        if (!visited[neighbor.val]) {
            dfs(neighbor, visited);
        }
    }
}

// 调用深度优先遍历
public void callDFS(Node node) {
    boolean[] visited = new boolean[n]; // n 为节点总数
    dfs(node, visited);
}

首先,定义一个节点类 Node,它包含节点的值 val 和链表形式的相邻节点列表 neighbors。然后,定义一个 dfs 函数来实现深度优先遍历。该函数需要两个参数:一个表示当前节点的 node 对象,另一个表示是否访问过当前节点的布尔值数组 visited

dfs 函数中,首先将当前节点标记为已访问,并输出节点值。然后,遍历当前节点的相邻节点,如果相邻节点没有被访问,则递归调用 dfs 函数访问该相邻节点。

最后,定义一个 callDFS 函数来调用 dfs 函数并传入节点对象。在 callDFS 函数中,创建一个 visited 布尔数组来记录节点是否访问过,然后调用 dfs 函数并传入根节点对象和 visited 数组。

使用 callDFS 函数来遍历整个图或树结构。

这是一个示例代码,用来遍历一个有序图结构:

public class DFSGraphTraversal {
    int n; // 节点总数
    List<Node> graph; // 有序图结构

    public DFSGraphTraversal(int n) {
        this.n = n;
        graph = new ArrayList<Node>();
        for (int i = 0; i < n; i++) {
            graph.add(new Node(i));
        }
    }

    // 添加有向边
    public void addEdge(int from, int to) {
        Node fromNode = graph.get(from);
        Node toNode = graph.get(to);
        fromNode.neighbors.add(toNode);
    }

    // 深度优先遍历
    public void dfs(Node node, boolean[] visited) {
        visited[node.val] = true;
        System.out.print(node.val + " ");

        for (Node neighbor : node.neighbors) {
            if (!visited[neighbor.val]) {
                dfs(neighbor, visited);
            }
        }
    }

    // 调用深度优先遍历
    public void callDFS(Node node) {
        boolean[] visited = new boolean[n];
        dfs(node, visited);
    }

    // 测试
    public static void main(String[] args) {
        DFSGraphTraversal traversal = new DFSGraphTraversal(6);
        traversal.addEdge(0, 1);
        traversal.addEdge(0, 2);
        traversal.addEdge(1, 3);
        traversal.addEdge(2, 3);
        traversal.addEdge(2, 4);
        traversal.addEdge(3, 5);
        traversal.addEdge(4, 5);

        traversal.callDFS(traversal.graph.get(0)); // 从第 0 个节点开始遍历
    }
}

在该示例代码中,首先创建一个 DFSGraphTraversal 对象,并在该对象中添加有向边。然后,调用 callDFS 函数来遍历整个图结构。

输出结果为:0 1 3 5 2 4,表示深度优先遍历的顺序。

在这里插入图片描述

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++创建图的数据结构以及图的深度优先遍历的介绍和演示: 1. 创建图的数据结构 在C++中,我们可以使用邻接矩阵或邻接表来表示图。邻接矩阵是一个二维数组,其中每个元素表示两个顶点之间是否有边。邻接表则是由每个顶点的邻接点列表组成的数组。每个邻接点列表包含与该顶点相邻的所有顶点。 下面是使用邻接表表示图的C++代码示例: ```c++ #include <iostream> #include <vector> using namespace std; // 邻接点结构体 struct AdjNode { int v; // 相邻顶点的下标 AdjNode* next; // 指向下一个邻接点的指针 AdjNode(int _v) : v(_v), next(nullptr) {} }; // 顶点结构体 struct Vertex { char data; // 顶点数据 AdjNode* first; // 指向第一个邻接点的指针 Vertex(char _data) : data(_data), first(nullptr) {} }; // 图结构体 struct Graph { vector<Vertex> Vex; // 顶点数组 int vexNum; // 顶点数 int edgeNum; // 边数 Graph(int n) : vexNum(n), edgeNum(0) { Vex.resize(n); } }; // 添加边 void addEdge(Graph& G, int u, int v) { AdjNode* node = new AdjNode(v); node->next = G.Vex[u].first; G.Vex[u].first = node; G.edgeNum++; } // 创建图 Graph createGraph() { int n, m; cout << "请输入顶点数和边数:"; cin >> n >> m; Graph G(n); cout << "请输入每个顶点的数据:"; for (int i = 0; i < n; i++) { char data; cin >> data; G.Vex[i] = Vertex(data); } cout << "请输入每条边的起点和终点(下标从0开始):" << endl; for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; addEdge(G, u, v); addEdge(G, v, u); // 无向图需要添加反向边 } return G; } ``` 2. 图的深度优先遍历 深度优先遍历是一种递归算法,它从图的某个顶点开始遍历,沿着一条路径访问未访问过的顶点,直到到达最后一个顶点,然后回溯到前一个顶点,继续访问其他未访问过的顶点,直到所有顶点都被访问过。 下面是使用邻接表表示图的深度优先遍历的C++代码示例: ```c++ // 深度优先遍历 void DFS(Graph G, int v, vector<bool>& vis) { cout << G.Vex[v].data << "\t"; // 输出或存储 vis[v] = true; AdjNode* p = G.Vex[v].first; while (p) { int w = p->v; if (!vis[w]) { DFS(G, w, vis); } p = p->next; } } // 深度优先遍历入口 void DFSTraverse(Graph G) { vector<bool> vis(G.vexNum, false); // 标记数组,记录每个顶点是否被访问过 cout << "深度优先遍历结果:" << endl; for (int i = 0; i < G.vexNum; i++) { if (!vis[i]) { DFS(G, i, vis); } } cout << endl; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值