数据结构与算法(十)深度优先搜索与广度优先搜索

2024-01-10 05:44

本文主要是介绍数据结构与算法(十)深度优先搜索与广度优先搜索,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

广度优先搜索


广度优先搜索:从一个顶点出发(由开始时顶点创造顺序优先决定),访问所有没有被访问过的临节点。然后在从被访问过的节点出发,重复之前的操作
如下为一个图

从1出发,先后访问2 3,之后2访问它的邻接点4,3访问它的邻接点5(因为4已经被访问过了,所有节点只访问一次),最后4访问6,因为5的邻接点4 6访问过了,所以5不再访问6.
由该途径可以得到一个树,叫做广度优先生成树, 如下图所示

该存储路径由一个队列的形式和一个辅助数组存储该点是否被访问


1已经出队,所以数组1位置存储true,此时入队1的邻接点2 3,此后每出列一个邻接点,该邻接点的邻接点入列,数组相应的存储true,直到最后一个邻接点出列,算法结束

图有两种状态:连通和不连通,图中各顶点不一定要连接
所有节点都有连接叫做连通图,否则叫做不连通图
如下有两个图,同样可以当作一个图处理,也可以广度优先遍历

深度优先搜索


深度优先搜索:类似于黏菌走迷宫,先沿一条路走,无路可走时再回退
如下图:

首先从顶点1开始,走到2(可以能走3),然后走4,5,此时发现无路可走,退回4,发现4走过了,回到2,发现6没有走,就走6,然后回到2,回到1,1的右侧路同左侧路一致,3 7 8直到走完 
在以上路线中依然有相应的数组去辅助访问,true或者false
此路径仍然可以以一个树来进行表示,叫做深度优先生成树:

该存储路径可由一个栈的形式和一个辅助数组存储该点是否被访问,现不具体表示

广度优先搜索代码实现


具体代码需要包含头文件<queue> STL中方法
应用:
std::queue<int>Q; 声明一个队列
Q.push(12); 传入12 
std::cout << Q.front() << std::endl;打印队列首位元素
Q.pop(); 弹出队列首位
Q.empty(); 检查队列是否为空

代码实现:

需要包含的头文件如下

#include <iostream>
#include <queue>

const int g_MaxCount = 100; 顶点最大值
bool visited[g_MaxCount]; 访问标志数组

typedef struct 存储数据
{
    char Vex[g_MaxCount]; 顶点
    int Edge[g_MaxCount][g_MaxCount]; 边
    int VexCount; 顶点总数
    int EdgeCount; 边总数
}AMGraph;

int locatecex(AMGraph G, char x) 查找顶点下标
{
    for (size_t i = 0; i < G.VexCount; i++)
    {
        if (x == G.Vex[i])
        {
            return i;
        }
    }
    return -1; 如果没有找到返回-1
}

void Create(AMGraph & G) 创建一个有向图的邻接矩阵
{
    std::cout << "G.VexCount" << std::endl;
    std::cin >> G.VexCount; 输入顶点总数
    std::cout << "G.EdgeCount" << std::endl;
    std::cin >> G.EdgeCount; 输入边总数
    for (size_t i = 0; i < G.VexCount; i++)
    {
        std::cin >> G.Vex[i]; 存储顶点
    }
    for (size_t i = 0; i < G.VexCount; i++) 
    {
        for (size_t j = 0; j < G.VexCount; j++)
        {
            G.Edge[i][j] = 0; 邻接矩阵内容全部初始化为0
        }
    }
    char cStart; 
    char cEnd; 两个临时变量
    int nStartIndex; 
    int nEndIndex; 存储获取后的下标

    while (G.EdgeCount--) 
    {
        std::cin >> cStart >> cEnd;
        nStartIndex = locatecex(G, cStart); 
        nEndIndex = locatecex(G, cEnd);
        if (nStartIndex != -1 && nEndIndex != -1)
        {
            //G.Edge[nStartIndex][nEndIndex] = G.Edge[nEndIndex][nStartIndex] = 1;无向图情况
            G.Edge[nStartIndex][nEndIndex] = 1;有向图情况
        }
        else
        {
            G.EdgeCount++; 输入错误的情况下,让该循坏的参数再次加1回到之前状态
        }
    }

}

void BFS(AMGraph G, int nIndex) 遍历 传入图和下标
{
    int QHeadValue; 一临时变量
    std::queue<int>Q; 使用队列
    visited[nIndex] = true; 表示当前顶点已经被访问
    Q.push(nIndex); 使数组相应位置元素加入队列
    while (!Q.empty()) 队列不空的情况下
    {
        QHeadValue = Q.front(); 存储元素的值
        Q.pop(); 弹出队列该值
        for (size_t i = 0; i < G.VexCount; i++)
        {
            if (G.Edge[QHeadValue][i] && !visited[i]) 
            {
                std::cout << G.Vex[i] << "\t"; 输出传入图下标
                visited[i] = true;
                Q.push(i); 传入队列中
            }
        }
    }
}

void print(AMGraph G) 遍历输出该图
{
    for (size_t i = 0; i < G.VexCount; i++)
    {
        for (size_t j = 0; j < G.VexCount; j++)
        {
            std::cout << G.Edge[i][j] << "\t";
        }
        std::cout << std::endl;
    }
}

int main()
{
    char szBuffer;
    AMGraph G;
    Create(G);
    print(G);
    std::cout << "input start node:" << std::endl;
    std::cin >> szBuffer; 输入遍历图的起点
    int nIndex = locatecex(G, szBuffer); 接受该起点获取下标
    if (nIndex != -1)
    {
        BFS(G, nIndex);
    }
    system("pause");
    return 0;
}
运行结果如下:包括遍历结果和邻接矩阵


深度优先搜索代码实现


具体代码实现同广度大致相同
需要包含的头文件如下

#include <iostream>
#include <queue>

const int g_MaxCount = 100;//顶点最大值
bool visited[g_MaxCount];//访问标志数组

typedef struct {
    char Vex[g_MaxCount];
    int Edge[g_MaxCount][g_MaxCount];
    int VexCount;
    int EdgeCount;
}AMGraph;

int locatecex(AMGraph G, char x)
{
    for (size_t i = 0; i < G.VexCount; i++)
    {
        if (x == G.Vex[i])
        {
            return i;
        }
    }
    return -1;
}

void Create(AMGraph & G)
{
    std::cout << "G.VexCount" << std::endl;
    std::cin >> G.VexCount;
    std::cout << "G.EdgeCount" << std::endl;
    std::cin >> G.EdgeCount;
    for (size_t i = 0; i < G.VexCount; i++)
    {
        std::cin >> G.Vex[i];
    }
    for (size_t i = 0; i < G.VexCount; i++)
    {
        for (size_t j = 0; j < G.VexCount; j++)
        {
            邻接矩阵内容全部初始化为0
            G.Edge[i][j] = 0;
        }
    }
    char cStart;
    char cEnd;
    int nStartIndex;
    int nEndIndex;

    while (G.EdgeCount--)
    {
        std::cin >> cStart >> cEnd;
        nStartIndex = locatecex(G, cStart);
        nEndIndex = locatecex(G, cEnd);
        if (nStartIndex != -1 && nEndIndex != -1)
        {
            //G.Edge[nStartIndex][nEndIndex] = G.Edge[nEndIndex][nStartIndex] = 1;
            G.Edge[nStartIndex][nEndIndex] = 1;
        }
        else
        {
            G.EdgeCount++;
        }
    }

}

void DFS(AMGraph G, int nIndex) 算法同广度有所修改
{
    std::cout << G.Vex[nIndex] << "\t"; 打印当前节点
    visited[nIndex] = true;
    for (size_t i = 0; i < G.VexCount; i++)
    {
        if (G.Edge[nIndex][i] && !visited[i])
        {
            DFS(G, i); 递归
        }
    }
}

void print(AMGraph G)
{
    for (size_t i = 0; i < G.VexCount; i++)
    {
        for (size_t j = 0; j < G.VexCount; j++)
        {
            std::cout << G.Edge[i][j] << "\t";
        }
        std::cout << std::endl;
    }
}

int main()
{
    char szBuffer;
    AMGraph G;
    Create(G);
    print(G);

    std::cout << "input start node:" << std::endl;
    std::cin >> szBuffer;
    int nIndex = locatecex(G, szBuffer);
    if (nIndex != -1)
    {
        DFS(G, nIndex);
    }
    system("pause");
    return 0;
}
运行结果如下:

这篇关于数据结构与算法(十)深度优先搜索与广度优先搜索的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/589744

相关文章

Python与DeepSeek的深度融合实战

《Python与DeepSeek的深度融合实战》Python作为最受欢迎的编程语言之一,以其简洁易读的语法、丰富的库和广泛的应用场景,成为了无数开发者的首选,而DeepSeek,作为人工智能领域的新星... 目录一、python与DeepSeek的结合优势二、模型训练1. 数据准备2. 模型架构与参数设置3

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Java深度学习库DJL实现Python的NumPy方式

《Java深度学习库DJL实现Python的NumPy方式》本文介绍了DJL库的背景和基本功能,包括NDArray的创建、数学运算、数据获取和设置等,同时,还展示了如何使用NDArray进行数据预处理... 目录1 NDArray 的背景介绍1.1 架构2 JavaDJL使用2.1 安装DJL2.2 基本操

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一