深度优先算法和广度优先算法

算法:深度优先算法和广度优先算法(基于邻接矩阵)

1.写在前面

  图的存储结构有两种:一种是基于二维数组的邻接矩阵表示法。

            另一种是基于链表的的邻接表。

  在邻接矩阵中,可以如下表示顶点和边连接关系:

    

说明:

  将顶点对应为下标,根据横纵坐标将矩阵中的某一位置值设为1,表示两个顶点向联接。

  图示表示的是无向图的邻接矩阵,从中我们可以发现它们的分布关于斜对角线对称

  我们在下面将要讨论的是下图的两种遍历方法(基于矩阵的):

    

  我们已经说明了我们要用到的是邻接矩阵表示法,那么我首先要来构造图:

  矩阵图的数据结构如下表示:

#define MaxVnum 50
typedef double AdjMatrix[MaxVnum][MaxVnum];   //表示一个矩阵,用来存储顶点和边连接关系
typedef struct {
    int vexnum,arcnum;               //顶点的个数,边的个数
    AdjMatrix arcs;                 //图的邻接矩阵
}Graph;

  这样我们可以首先来创建上述图,为了方便,我们直接在代码中书写矩阵,而不用每次调试手动输入了

void CreateGraph(Graph &G)
{
    G.vexnum=8;
    G.arcnum=9;
    G.arcs[0][1]=1;
    G.arcs[0][2]=1;
    G.arcs[1][3]=1;
    G.arcs[1][4]=1;
    G.arcs[2][5]=1;
    G.arcs[2][6]=1;
    G.arcs[3][1]=1;
    G.arcs[3][7]=1;
    G.arcs[3][6]=1;
    G.arcs[4][1]=1;
    G.arcs[4][7]=1;
    G.arcs[5][2]=1;
    G.arcs[5][6]=1;
    G.arcs[5][5]=1;
    G.arcs[6][2]=1;
    G.arcs[6][5]=1;
    G.arcs[7][3]=1;
    G.arcs[7][4]=1;
}

  这样我们就已经完成了准备工作,我们可以正式来学习我们的两种遍历方式了。

2.深度优先遍历算法

  分析深度优先遍历

    从图的某个顶点出发,访问图中的所有顶点且使每个顶点仅被访问一次。这一过程叫做图的遍历。

    深度优先搜索的思想:

      ①访问顶点v;
      ②依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
      ③若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

    比如:

    

    在这里为了区分已经访问过的节点和没有访问过的节点,我们引入一个一维数组bool visited[MaxVnum]用来表示与下标对应的顶点是否被访问过,

流程:
? 首先输出 V1,标记V1的flag=true;
? 获得V1的邻接边 [V2 V3],取出V2,标记V2的flag=true;
? 获得V2的邻接边[V1 V4 V5],过滤掉已经flag的,取出V4,标记V4的flag=true;
? 获得V4的邻接边[V2 V8],过滤掉已经flag的,取出V8,标记V8的flag=true;
? 获得V8的邻接边[V4 V5],过滤掉已经flag的,取出V5,标记V5的flag=true;
? 此时发现V5的所有邻接边都已经被flag了,所以需要回溯。(左边黑色虚线,回溯到V1,回溯就是下层递归结束往回返)

? 回溯到V1,在前面取出的是V2,现在取出V3,标记V3的flag=true;
? 获得V3的邻接边[V1 V6 V7],过滤掉已经flag的,取出V6,标记V6的flag=true;
? 获得V6的邻接边[V3 V7],过滤掉已经flag的,取出V7,标记V7的flag=true;
? 此时发现V7的所有邻接边都已经被flag了,所以需要回溯。(右边黑色虚线,回溯到V1,回溯就是下层递归结束往回返)

  深度优先搜索的代码

bool visited[MaxVnum];
void DFS(Graph G,int v)
{
    visited[v]= true; //从V开始访问,flag它
    printf("%d",v);    //打印出V
    for(int j=0;j<G.vexnum;j++)
        if(G.arcs[v][j]==1&&visited[j]== false) //这里可以获得V未访问过的邻接点
            DFS(G,j); //递归调用,如果所有节点都被访问过,就回溯,而不再调用这里的DFS
}

void DFSTraverse(Graph G) {
    for (int v = 0; v < G.vexnum; v++)
        visited[v] = false; //刚开始都没有被访问过

    for (int v = 0; v < G.vexnum; ++v)
        if (visited[v] == false) //从没有访问过的第一个元素来遍历图
            DFS(G, v);
}

3.广度优先搜索算法

    分析广度优先遍历    

      所谓广度,就是一层一层的,向下遍历,层层堵截,还是这幅图,我们如果要是广度优先遍历的话,我们的结果是V1 V2 V3 V4 V5 V6 V7 V8。

      

      广度优先搜索的思想:

         ① 访问顶点vi ;

         ② 访问vi 的所有未被访问的邻接点w1 ,w2 , …wk ;

         ③ 依次从这些邻接点(在步骤②中访问的顶点)出发,访问它们的所有未被访问的邻接点; 依此类推,直到图中所有访问过的顶点的邻接点都被访问;

   说明:

      为实现③,需要保存在步骤②中访问的顶点,而且访问这些顶点的邻接点的顺序为:先保存的顶点,其邻接点先被访问。 这里我们就想到了用标准模板库中的queue队列来实现这种先进现出的服务。

      老规矩我们还是走一边流程:

   说明: 

     ?将V1加入队列,取出V1,并标记为true(即已经访问),将其邻接点加进入队列,则 <—[V2 V3] 

     ?取出V2,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[V3 V4 V5]

?取出V3,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[V4 V5 V6 V7]

?取出V4,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[V5 V6 V7 V8]

?取出V5,并标记为true(即已经访问),因为其邻接点已经加入队列,则 <—[V6 V7 V8]

?取出V6,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[V7 V8]

?取出V7,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[V8]

?取出V8,并标记为true(即已经访问),将其未访问过的邻接点加进入队列,则 <—[]

  广度优先搜索的代码

#include <queue>
using namespace std;
....
void BFSTraverse(Graph G)
{
    for (int v=0;v<G.vexnum;v++) //先将其所有顶点都设为未访问状态
        visited[v]=false;
    queue<int> Q;
    for(int v=0;v<G.vexnum;v++)
    {
        if(visited[v]==false)   //若该点没有访问
        {
            Q.push(v);    //将其加入到队列中
            visited[v]=true;
            while (!Q.empty())  //只要队列不空,遍历就没有结束
            {
                int t =Q.front();  //取出对头元素
                Q.pop();
                printf(" %d ",t+1);
                for(int j=0;j<G.vexnum;j++) //将其未访问过的邻接点加进入队列
                    if(G.arcs[t][j]==1&&visited[j]== false)
                    {
                        Q.push(j);
                        visited[j]=true; //在这里要设置true,因为这里该顶点我们已经加入到了队列,为了防止重复加入!
                    }
            }
        }
    }
}

两种算法的复杂度分析

  深度优先

    数组表示:查找所有顶点的所有邻接点所需时间为O(n2),n为顶点数,算法时间复杂度为O(n2)   

  广度优先

    数组表示:查找每个顶点的邻接点所需时间为O(n2),n为顶点数,算法的时间复杂度为O(n2)

      

分类: C/C++,数据结构,算法第四版

时间: 2024-10-05 23:09:28

深度优先算法和广度优先算法的相关文章

邻接表的深度优先算法和广度优先算法--p140和p142

源程序: #include <stdio.h>#include <stdlib.h> #define vnum 100 typedef char VerTexType; //定义链接队列的结点typedef struct LinkQueueNode{ int data1; struct LinkQueueNode *next;}LKQueNode; //定义队列,队列有头指针和尾指针typedef struct LKQueue{ LinkQueueNode *front,*rear

OpenCV二值图求最大连通区域算法(广度优先算法 BFS)

#include <iostream> #include <opencv2\opencv.hpp> #include <vector> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <windows.h> #include <math.h> #include <queue> using namespace std;usin

树图 广度优先算法和深度优先算法

原文链接: ????????深度优先算法:http://blog.163.com/zhoumhan_0351/blog/static/3995422720098342257387/ ????????广度优先算法:http://blog.163.com/zhoumhan_0351/blog/static/3995422720098711040303/ 树图 广度优先算法和深度优先算法

深度优先与广度优先算法

图的遍历有深度优先和广度优先算法. 深度优先遍历可描述为一个递归算法.当到达顶点v时,具体操作是: ①访问(v); ②for(与v相邻的每个顶点w) 遍历(w): //深度优先算法 template<int max_size> void Diagraph<max_size>::depth_first(void(*visit)(Vertex &)) const { bool visited[max_size]; //引入数组防止无限循环 Vertex v; for (all

图的遍历方法(深度优先和广度优先算法)

图的遍历方法有两种: 1 深度优先 该算法类似于树的先根遍历: 2   广度优先 该算法类似树的层次遍历: 事例: 深度优先遍历顺序为:V1–V2–V4–V8–V5–V3–V6–V7 广度优先遍历顺序为:V1–V2–V3–V4–V5–V6–V7–V8 3   注意事项 1)一个图,它的深度优先和广度优先是不唯一的,可以有多个! 2)一般情况都是给邻接表或者邻接矩阵求深度优先和广度优先,此时,深度优先和广度优先都是唯一的了,因为当你的存储结构固定的时候,深度优先和广度优先也随之被固定了!

十大基础实用算法之深度优先搜索和广度优先搜索

深度优先搜索算法(Depth-First-Search),是搜索算法的一种.它沿着树的深度遍历树的节点,尽可能深的搜索树的分支.当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点.这一过程一直进行到已发现从源节点可达的所有节点为止.如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止.DFS属于盲目搜索. 深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相

深度优先算法+广度优先算法

一 深度优先算法 bool visited[MaxVnum]; void DFS(Graph G,int v) { visited[v]= true; //从V开始访问,flag它 printf("%d",v); //打印出V for(int j=0;j<G.vexnum;j++) if(G.arcs[v][j]==1&&visited[j]== false) //这里可以获得V未访问过的邻接点 DFS(G,j); //递归调用,如果所有节点都被访问过,就回溯,而

深度优先和广度优先算法

1.深度优先算法 遍历规则:不断地沿着顶点的深度方向遍历.顶点的深度方向是指它的邻接点方向. 最后得出的结果为:ABDECFHG. Python代码实现的伪代码如下: 2.广度优先算法: 遍历规则: 1)先访问完当前顶点的所有邻接点.(应该看得出广度的意思) 2)先访问顶点的邻接点先于后访问顶点的邻接点被访问. 最后得出的结果为:ABCDEFGH. Python代码实现的伪代码如下: 3.总结 深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个结点只能访问一次.要特别注意的是,二

算法_图的深度优先搜索和广度优先搜索

一.图的基本数据结构 图是由一组顶点和一组能够将两个顶点相互连接的边所构成的,一般使用0~V-1这样的数字形式来表示一张含有V个顶点的图.用v-w来指代一张图的边,由于是无向图,因此v-w和w-v是同一种边的两种表示方法.无向图是指边没有方向的图结构在无向图中,边仅仅表示的是两个顶点之间的连接.图的数据结构的可视化如下图所示(其中边上的箭头没有任何意义): 当两个顶点通过一条边相互连接,则称这两个顶点是相邻的.某个顶点的度数即为依附它的边的总数.当两个顶点之间存在一条连接双方的路径的时候,称为这