BFS(邻接矩阵+队列)和DFS(邻接表+栈)C++实现

简介: BFS(邻接矩阵+队列)和DFS(邻接表+栈)C++实现

5.2 图的遍历


5.2.1 广度优先搜索

概念

广度优先搜索(也称宽度优先搜索,缩写BFS)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。


基本步骤

1.给出一连通图,如图,初始化全是白色(未访问);

2.搜索起点V1(灰色);


3.已搜索V1(黑色),即将搜索V2,V3,V4(标灰);

4.对V2,V3,V4重复以上操作;


5.直到终点V7被染灰,终止;


模板

/* 
通过邻接矩阵实现BFS
*/
#include <iostream>
#include <queue>
using namespace std;
#define MaxVertexNum 10
struct Graph
{
    int vertexnum;
    int edgenum;
    bool visit[MaxVertexNum];
    int edgeList[MaxVertexNum][MaxVertexNum];
};
void BuildGraph(Graph *G)
{
    int start, end;
    cout << "Please enter the number of vertices and edges" << endl;
    cin >> G->vertexnum >> G->edgenum;
    // 图的权重初始化
    for (int i = 0; i < G->vertexnum; i++)
    {
        G->visit[i] = false;
        for (int j = 0; j < G->vertexnum; j++)
        {
            G->edgeList[i][j] = 0;
        }
    }
    // 输入权重信息
    for (int i = 0; i < G->edgenum; i++)
    {
        cout << "Please enter the Start number, end number, weight" << endl;
        cin >> start >> end;
        cin >> G->edgeList[start][end];
        G->edgeList[end][start] = G->edgeList[start][end];
    }
    cout << endl;
}
void BFS(Graph *G)
{
    queue<int> q;
    G->visit[0] = true;
    q.push(0);
    while (!q.empty())
    {
        int tmp = q.front();
        q.pop();
        for (int i = 0; i < G->vertexnum; i++)
        {
            if (G->edgeList[tmp][i] && !G->visit[i])
            {
                G->visit[i] = true;
                q.push(i);
                cout << i << "Visited" << endl;
            }
        }
    }
}
int main()
{
    Graph G;
    BuildGraph(&G);
    BFS(&G);
    cout << endl;
    system("pause");
    return 0;
}
/* 
7 9
0 2 1
0 1 1
0 3 1
1 2 1
2 3 1
2 4 1
3 6 1
1 5 1
5 6 1
*/


总结

广度优先搜索就是访问根结点相邻的所有结点,同时相邻的结点被访问后进入队列,然后依次出队,访问所有未访问结点。类似与水波一圈一圈荡开的结构。


5.2.2 深度优先搜索

概念

深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。


基本步骤

1.对于下面的树而言,DFS方法首先从根节点1开始

2.从stack中访问栈顶的点;


3.找出与此点邻接的且尚未遍历的点,进行标记,然后放入stack中,依次进行;


4.如果此点没有尚未遍历的邻接点,则将此点从stack中弹出,再按照(3)依次进行;



5.直到遍历完整个树,stack里的元素都将弹出,最后栈为空,DFS遍历完成。



模板

/* 
通过邻接表实现DFS
*/
#include 
#include 
using namespace std;
#define MaxVertexNum 10
struct EdgeNode
{
    int adjvex;
    EdgeNode *next;
};
struct VertexNode
{
    EdgeNode *firstedge;
};
struct Graph
{
    int vertexnum;
    int edgenum;
    VertexNode vertexList[MaxVertexNum];
    bool visit[MaxVertexNum];
};
void BuildGraph(Graph *G)
{
    int start, end, weight;
    EdgeNode *newnode;
    cout << "Please enter the number of vertices and edges" << endl;
    cin >> G->vertexnum >> G->edgenum;
    // 图的顶点数据
    for (int i = 0; i < G->vertexnum; i++)
    {
        G->vertexList[i].firstedge = NULL;
        G->visit[i] = false;
    }
    // 输入权重信息
    for (int i = 0; i < G->edgenum; i++)
    {
        cout << "Please enter the Start number, end number" << endl;
        cin >> start >> end;
        //start-->end
        newnode = new EdgeNode;
        newnode->adjvex = end;
        newnode->next = G->vertexList[start].firstedge;
        G->vertexList[start].firstedge = newnode;
        // end-->start
        newnode = new EdgeNode;
        newnode->adjvex = start;
        newnode->next = G->vertexList[end].firstedge;
        G->vertexList[end].firstedge = newnode;
    }
}
void Print_Adjacency_Matrix(Graph G)
{
    for (int i = 0; i < G.vertexnum; i++)
    {
        cout << i << '\t';
        EdgeNode *p = G.vertexList[i].firstedge;
        while (p)
        {
            printf("adjvex:%d  ", p->adjvex);
            p = p->next;
        }
        cout << endl;
    }
}
void DFS(Graph *G)
{
    stack s;
    s.push(0);
    G->visit[0] = true;
    while (!s.empty())
    {
        int tmp = s.top();
        EdgeNode *p = G->vertexList[tmp].firstedge;
        while (p)
        {
            if (G->visit[p->adjvex])
            {
                p = p->next;
            }
            else
            {
                cout << "-->" << p->adjvex;
                s.push(p->adjvex);
                G->visit[p->adjvex] = true;
                // 找到下一深度的点就不再周边广搜
                break;
            }
            // 周围没有待访问的点,出栈
            if (p == NULL)
            {
                s.pop();
            }
        }
    }
}
int main()
{
    Graph G;
    BuildGraph(&G);
    Print_Adjacency_Matrix(G);
    DFS(&G);
    cout << endl;
    system("pause");
    return 0;
}
/*  
9 10
0 1
0 7
1 2
1 4
7 5 
7 8
2 3
4 3
5 3
5 6
*/


总结

深度优先搜索就是一条道走到黑,然后到无路可走的时候回头。所以说最后会回溯所有的点。

目录
相关文章
|
2月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
158 77
|
5天前
|
存储 算法 C++
【c++丨STL】priority_queue(优先级队列)的使用与模拟实现
本文介绍了STL中的容器适配器`priority_queue`(优先级队列)。`priority_queue`根据严格的弱排序标准设计,确保其第一个元素始终是最大元素。它底层使用堆结构实现,支持大堆和小堆,默认为大堆。常用操作包括构造函数、`empty`、`size`、`top`、`push`、`pop`和`swap`等。我们还模拟实现了`priority_queue`,通过仿函数控制堆的类型,并调用封装容器的接口实现功能。最后,感谢大家的支持与关注。
24 1
|
2月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
50 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
2月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
51 9
|
2月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
43 7
|
4月前
|
缓存 安全 C++
C++无锁队列:解锁多线程编程新境界
【10月更文挑战第27天】
197 7
|
4月前
|
消息中间件 存储 安全
|
4月前
|
存储 设计模式 C++
【C++】优先级队列(容器适配器)
本文介绍了C++ STL中的线性容器及其适配器,包括栈、队列和优先队列的设计与实现。详细解析了`deque`的特点和存储结构,以及如何利用`deque`实现栈、队列和优先队列。通过自定义命名空间和类模板,展示了如何模拟实现这些容器适配器,重点讲解了优先队列的内部机制,如堆的构建与维护方法。
68 0
|
13天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
16天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)