热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

1.写在前面图的存储结构有两种:一种是基于二维数组的邻接矩阵表示法。另一种是基于链表的的邻接表。在邻接矩阵中,可以如下表示顶点和边连接关系:

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有路径相通的顶点都被访问;
      ③若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

    比如:

    

    在这里为了区分已经访问过的节点和没有访问过的节点,我们引入一个一维数组boolvisited[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); //打印出Vfor(int j=0;j}void DFSTraverse(Graph G) {for (int v = 0; v }

 3.广度优先搜索算法

    分析广度优先遍历    

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

      

      广度优先搜索的思想:

         ① 访问顶点vi ;

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

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

   说明:

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

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

   说明: 

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

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

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

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

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

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

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

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

  广度优先搜索的代码

#include
using namespace std;
....
void BFSTraverse(Graph G)
{for (int v&#61;0;v Q;for(int v&#61;0;v}

 两种算法的复杂度分析

  深度优先

    数组表示&#xff1a;查找所有顶点的所有邻接点所需时间为O(n2)&#xff0c;n为顶点数&#xff0c;算法时间复杂度为O(n2)   

  广度优先

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



推荐阅读
  • MySQL InnoDB 存储引擎索引机制详解
    本文深入探讨了MySQL InnoDB存储引擎中的索引技术,包括索引的基本概念、数据结构与算法、B+树的特性及其在数据库中的应用,以及索引优化策略。 ... [详细]
  • 本文将深入探讨 Unreal Engine 4 (UE4) 中的距离场技术,包括其原理、实现细节以及在渲染中的应用。距离场技术在现代游戏引擎中用于提高光照和阴影的效果,尤其是在处理复杂几何形状时。文章将结合具体代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文介绍如何手动实现一个字符串连接函数,该函数不依赖于C语言的标准字符串处理函数,如strcpy或strcat。函数原型为void concatenate(char *dest, char *src),其主要作用是将源字符串src追加到目标字符串dest的末尾。 ... [详细]
  • 二叉搜索树转换为排序双向链表的面试题解析
    本文探讨了一道经典的面试问题,即将给定的一棵二叉搜索树转换为一个排序的双向链表,过程中不允许创建新节点,仅能通过调整现有节点的指针来实现转换。 ... [详细]
  • 本文介绍了在Linux环境下如何有效返回命令行状态、上一级目录及快速查找头文件和函数定义的方法。包括处理长时间运行命令、编辑器退出技巧、目录导航以及文件搜索策略。 ... [详细]
  • 本文通过分析一个具体的案例,探讨了64位Linux系统对32位应用程序的兼容性问题。案例涉及OpenVPN客户端在64位系统上的异常行为,通过逐步排查和代码测试,最终定位到了与TUN/TAP设备相关的系统调用兼容性问题。 ... [详细]
  • c语言二元插值,二维线性插值c语言
    c语言二元插值,二维线性插值c语言 ... [详细]
  • 本文详细介绍了如何在循环双链表的指定位置插入新元素的方法,包括必要的步骤和代码示例。 ... [详细]
  • PHP面试题精选及答案解析
    本文精选了新浪PHP笔试题及最新的PHP面试题,并提供了详细的答案解析,帮助求职者更好地准备PHP相关的面试。 ... [详细]
  • 探讨了在VB中使用WebBrowser控件时遇到的‘无法找到或打开C:\WINDOWS\system32\ieframe.dll’问题,并提供了解决方案。 ... [详细]
  • 本题要求实现一个高效的算法,在一个 m x n 的矩阵中搜索目标值 target。该矩阵具有以下特性:每行的元素从左到右按升序排列,每列的元素从上到下按升序排列。 ... [详细]
  • 深入解析RelativeLayout、LinearLayout与FrameLayout的性能差异
    本文详细分析了FrameLayout和LinearLayout的性能对比,通过具体的测量数据和源码解析,探讨了不同布局在不同场景下的性能表现。 ... [详细]
  • 3.[15]Writeaprogramtolistallofthekeysandvaluesin%ENV.PrinttheresultsintwocolumnsinASCIIbet ... [详细]
  • 本篇文章详细探讨了微机原理实验中的指令系统,特别是第三章的内容。对于希望深入了解微机工作原理和技术实现的朋友来说,这是一篇不可多得的技术指南。文章不仅涵盖了基础概念,还深入讲解了指令格式、操作数类型以及各种寻址方式,旨在帮助读者更好地掌握微机指令系统的应用。 ... [详细]
  • 本文介绍如何使用JavaScript中的for循环来创建一个九九乘法表,适合初学者学习循环结构的应用。 ... [详细]
author-avatar
林振萍俊諭
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有