深度优先搜索和广度优先搜索

转载自  深度优先搜索和广度优先搜索

图的应用很广泛,也有很多非常有用的算法,当然也有很多待解决的问题,根据性质,图可以分为无向图和有向图。

之所以要研究图,是因为图在生活中应用比较广泛:

图是若干个顶点(Vertices)和边(Edges)相互连接组成的。边仅由两个顶点连接,并且没有方向的图称为无向图。 在研究图之前,有一些定义需要明确,下图中表示了图的一些基本属性的含义,这里就不多说明。

在研究图之前,我们需要选用适当的数据结构来表示图,有时候,我们常被我们的直觉欺骗,如下图,这两个其实是一样的,这其实也是一个研究问题,就是如何判断图的形态。

要用计算机处理图,我们可以抽象出以下的表示图的API:

Graph的API的实现可以由多种不同的数据结构来表示,最基本的是维护一系列边的集合,如下:

还可以使用邻接矩阵来表示:

也可以使用邻接列表来表示:

由于采用如上方式具有比较好的灵活性,采用邻接列表来表示的话,可以定义如下数据结构来表示一个Graph对象。

public class Graph
{private readonly int verticals;//顶点个数private int edges;//边的个数private List<int>[] adjacency;//顶点联接列表public Graph(int vertical){this.verticals = vertical;this.edges = 0;adjacency=new List<int>[vertical];for (int v = 0; v < vertical; v++){adjacency[v]=new List<int>();}}public int GetVerticals (){return verticals;}public int GetEdges(){return edges;}public void AddEdge(int verticalStart, int verticalEnd){adjacency[verticalStart].Add(verticalEnd);adjacency[verticalEnd].Add(verticalStart);edges++;}public List<intGetAdjacency(int vetical){return adjacency[vetical];}
}

图也分为稀疏图和稠密图两种,如下图:

在这两个图中,顶点个数均为50,但是稀疏图中只有200个边,稠密图中有1000个边。在现实生活中,大部分都是稀疏图,即顶点很多,但是顶点的平均度比较小。

采用以上三种表示方式的效率如下:

在讨论完图的表示之后,我们来看下在图中比较重要的一种算法,即深度优先算法。

深度优先算法

在谈论深度优先算法之前,我们可以先看看迷宫探索问题。下面是一个迷宫和图之间的对应关系:

迷宫中的每一个交会点代表图中的一个顶点,每一条通道对应一个边。

迷宫探索可以采用Trémaux绳索探索法。即:

  • 在身后放一个绳子

  • 访问到的每一个地方放一个绳索标记访问到的交会点和通道

  • 当遇到已经访问过的地方,沿着绳索回退到之前没有访问过的地方:

     

图示如下:

下面是迷宫探索的一个小动画:

深度优先搜索算法模拟迷宫探索。在实际的图处理算法中,我们通常将图的表示和图的处理逻辑分开来。所以算法的整体设计模式如下:

  • 创建一个Graph对象

  • 将Graph对象传给图算法处理对象,如一个Paths对象

  • 然后查询处理后的结果来获取信息

下面是深度优先的基本代码,我们可以看到,递归调用dfs方法,在调用之前判断该节点是否已经被访问过。

public class DepthFirstSearch
{private bool[] marked;//记录顶点是否被标记private int count;//记录查找次数private DepthFirstSearch(Graph g, int v){marked = new bool[g.GetVerticals()];dfs(g, v);}private void dfs(Graph g, int v){marked[v] = true;count++;foreach (int vertical in g.GetAdjacency(v)){if (!marked[vertical])dfs(g,vertical);}}public bool IsMarked(int vertical){return marked[vertical];}public int Count(){return count;}
}

试验一个算法最简单的办法是找一个简单的例子来实现。

有了这个基础,我们可以实现基于深度优先的路径查询,要实现路径查询,我们必须定义一个变量来记录所探索到的路径。

 

所以在上面的基础上定义一个edgesTo变量来后向记录所有到s的顶点的记录,和仅记录从当前节点到起始节点不同,我们记录图中的每一个节点到开始节点的路径。为了完成这一日任务,通过设置edgesTo[w]=v,我们记录从v到w的边,换句话说,v-w是做后一条从s到达w的边。 edgesTo[]其实是一个指向其父节点的树。

public class DepthFirstPaths
{private bool[] marked;//记录是否被dfs访问过private int[] edgesTo;//记录最后一个到当前节点的顶点private int s;//搜索的起始点public DepthFirstPaths(Graph g, int s){marked = new bool[g.GetVerticals()];edgesTo = new int[g.GetVerticals()];this.s = s;dfs(g, s);}private void dfs(Graph g, int v){marked[v] = true;foreach (int w in g.GetAdjacency(v)){if (!marked[w]){edgesTo[w] = v;dfs(g,w);}}}public bool HasPathTo(int v){return marked[v];}public Stack<intPathTo(int v){if (!HasPathTo(v)) return null;Stack<int> path = new Stack<int>();for (int x = v; x!=s; x=edgesTo[x]){path.Push(x);}path.Push(s);return path;}
}

 

上图中是黑色线条表示 深度优先搜索中,所有定点到原点0的路径, 他是通过edgeTo[]这个变量记录的,可以从右边可以看出,他其实是一颗树,树根即是原点,每个子节点到树根的路径即是从原点到该子节点的路径。

下图是深度优先搜索算法的一个简单例子的追踪。 

通常我们更关注的是一类单源最短路径的问题,那就是给定一个图和一个源S,是否存在一条从s到给定定点v的路径,如果存在,找出最短的那条(这里最短定义为边的条数最小)

深度优先算法是将未被访问的节点放到一个堆中(stack),虽然在上面的代码中没有明确在代码中写stack,但是 递归 间接的利用递归堆实现了这一原理。

 广度优先算法

和深度优先算法不同, 广度优先是将所有未被访问的节点放到了队列中。其主要原理是:

  • 将 s放到FIFO中,并且将s标记为已访问

  • 重复直到队列为空

     

  1. 移除最近最近添加的顶点v

  2. 将v未被访问的节点添加到队列中

  3. 标记他们为已经访问

     

广度优先是以距离递增的方式来搜索路径的。

class BreadthFirstSearch
{private bool[] marked;private int[] edgeTo;private int sourceVetical;//Source verticalpublic BreadthFirstSearch(Graph g, int s){marked=new bool[g.GetVerticals()];edgeTo=new int[g.GetVerticals()];this.sourceVetical = s;bfs(g, s);}private void bfs(Graph g, int s){Queue<intqueue = new Queue<int>();marked[s] = true;queue.Enqueue(s);while (queue.Count()!=0){int v = queue.Dequeue();foreach (int w in g.GetAdjacency(v)){if (!marked[w]){edgeTo[w] = v;marked[w] = true;queue.Enqueue(w);}}}}public bool HasPathTo(int v){return marked[v];}public Stack<int> PathTo(int v){if (!HasPathTo(v)) return null;Stack<int> path = new Stack<int>();for (int x = v; x!=sourceVetical; x=edgeTo[x]){path.Push(x);}path.Push(sourceVetical);return path;}}

广度优先算法的搜索步骤如下:

广度优先搜索首先是在距离起始点为1的范围内的所有邻接点中查找有没有到达目标结点的对象,如果没有,继续前进在距离起始点为2的范围内查找,依次向前推进。

本文简要介绍了无向图中的深度优先和广度优先算法,这两种算法时图处理算法中的最基础算法,也是后续更复杂算法的基础。其中图的表示,图算法与表示的分离这种思想在后续的算法介绍中会一直沿用,下文将讲解无向图中深度优先和广度优先的应用,以及利用这两种基本算法解决实际问题的应用。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/327319.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

消息队列 Kafka 的基本知识及 .NET Core 客户端

前言 最新项目中要用到消息队列来做消息的传输&#xff0c;之所以选着 Kafka 是因为要配合其他 java 项目中&#xff0c;所以就对 Kafka 了解了一下&#xff0c;也算是做个笔记吧。 本篇不谈论 Kafka 和其他的一些消息队列的区别&#xff0c;包括性能及其使用方式。 简介 Kafka…

深入解读Service Mesh背后的技术细节

转载自 深入解读Service Mesh背后的技术细节 在Kubernetes称为容器编排的标准之后&#xff0c;Service Mesh开始火了起来&#xff0c;但是很多文章讲概念的多&#xff0c;讲技术细节的少&#xff0c;所以专门写一篇文章&#xff0c;来解析Service Mesh背后的技术细节。 一、…

CentOS7查看和关闭防火墙

https://blog.csdn.net/ytangdigl/article/details/79796961 CentOS7查看和关闭防火墙 蔚蓝色天空sky 2018-04-02 23:22:21 708762 收藏 236 分类专栏&#xff1a; linux 文章标签&#xff1a; centos 防火墙 CentOS 7.0默认使用的是firewall作为防火墙 查看防火墙状态 f…

Visual Studio Code 1.8版本添加了Hot Exit、Zen Mode及更多调试选项

最新发布的Visual Studio Code 1.8版本有许多改进和新功能&#xff0c;包括防止丢失任何编辑信息的Hot Exit&#xff0c;方便开发人员把注意力集中在代码上的Zen Mode&#xff0c;新的调试功能以及更方便的设置等。 Hot Exit是一项新功能&#xff0c;目的是在应用程序崩溃或退出…

ElasticSearch(笔记)

简介 本教程基于ElasticSearch7.6.1, 注意ES7的语法与ES6的API调用差别很大, 教程发布时最新版本为ES7.6.2(20200401更新);ES是用于全文搜索的工具: SQL: 使用like %关键词%来进行模糊搜索在大数据情况下是非常慢的, 即便设置索引提升也有限;ElasticSearch: 搜索引擎(baidu, …

漫画:什么是冒泡排序

转载自 漫画&#xff1a;什么是冒泡排序 什么是冒泡排序&#xff1f; 冒泡排序的英文Bubble Sort&#xff0c;是一种最基础的交换排序。 大家一定都喝过汽水&#xff0c;汽水中常常有许多小小的气泡&#xff0c;哗啦哗啦飘到上面来。这是因为组成小气泡的二氧化碳比水要轻…

CentOS - 修改主机名教程(将 localhost.localdomain 改成其它名字)

https://www.cnblogs.com/gudi/p/7846978.html 需要关闭防火墙&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; Linux修改主机名称 碰到这个问题的时候&#xff0c;是在安装Zookeeper集群的时候&#xff0c;碰到如下问题 java.net.U…

.net core 源码解析-web app是如何启动并接收处理请求(二) kestrel的启动

上篇讲到.net core web app是如何启动并接受请求的&#xff0c;下面接着探索kestrel server是如何完成此任务的。 1.kestrel server的入口KestrelServer.Start (Microsoft.AspNetCore.Hosting.Server.IHttpApplication ) FrameFactory创建的frame实例最终会交给libuv的loop回调…

MySQL中的any_value()函数

https://blog.csdn.net/u014079773/article/details/93722761 https://www.thinbug.com/q/37089347 https://blog.csdn.net/Peacock__/article/details/90608246 https://www.itranslater.com/qa/details/2109775246877262848 4.any_value()会选择被分到同一组的数据里…

MybatisPlus使用

Mybatisplus 导入依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</gro…

.net core 源码解析-mvc route的注册,激活,调用流程(三)

.net core mvc route的注册&#xff0c;激活&#xff0c;调用流程 mvc的入口是route&#xff0c;当前请求的url匹配到合适的route之后&#xff0c;mvc根据route所指定的controller和action激活controller并调用action完成mvc的处理流程。下面我们看看服务器是如何调用route的。…

高可用性的几个级别

转载自 高可用性的几个级别 大家常说高可用&#xff0c;High Availablility&#xff0c;但是一般说到这个词的时候&#xff0c;具体指的什么方案呢&#xff1f; 级别一&#xff1a;FT (Fault Tolerance) 双击热备 通过创建与主实例保持虚拟同步的虚拟机&#xff0c;使应用在服…

mysql - Docker Wordpress连接到本地主机上的数据库服务器

视频上面的 docker service create --name mysql -p 3306:3306 --env MYSQL_ROOT_PASSWORDroot \ --env MYSQL_DATABASEwordpress \ --network demo \ --mount typevolume,sourcemysql-data,destination/var/lib/mysql \ mysql:5.7 docker service create -…

CoreCRM 开发实录——开始之新项目的技术选择

2016年11月&#xff0c;接受了一个工作&#xff0c;是对“悟空CRM”进行一些修补。这是一个不错的 CRM&#xff0c;开源&#xff0c;并提供一个 SaaS 的服务。正好微软的 .NET Core 和 ASP.NET Core 也发布了。于是就有了这个想法&#xff1a;使用 ASP.NET Core 来开发一个 CRM…

80%的程序员都不了解的调试技巧

转载自 80%的程序员都不了解的调试技巧 程序员的工作内容&#xff0c;除了大部分时间写代码之外&#xff0c;因为有不少的时间是用在调试代码上。甚至说不是在调试代码&#xff0c;就是即将调试代码。 :) 今天我们来谈谈调试代码的一些技巧&#xff0c;在使用IDE提供的debu…

复制vmware overLay网络无法ping通 ping www.baidu.com可以

因为忘记关闭防火墙了&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 要永久关闭&#xff01;&#xff01; 修改hostname https://blog.csdn.net/qq_27327261/article/details/109100219 关闭防火墙 https://blog.csdn.net/qq_27327261/article/details/1…

2016.NET Core相关内容回顾

每一年的脚步的确是快&#xff0c;转眼间马上就2017。.NET Core 2014年宣布开源以来&#xff0c;在2016年发布了第一个版本&#xff0c;2017年将发布第二个版本&#xff0c;在这新年之际&#xff0c;我们回顾2016年&#xff0c;新的一年&#xff0c;带着理想和抱负继续出发。 1…

微服务化的数据库设计与读写分离

转载自 微服务化的数据库设计与读写分离 数据库永远是应用最关键的一环&#xff0c;同时越到高并发阶段&#xff0c;数据库往往成为瓶颈&#xff0c;如果数据库表和索引不在一开始就进行良好的设计&#xff0c;则后期数据库横向扩展&#xff0c;分库分表都会遇到困难。 对于…

centos7 切换中文输入法 无需安装

*************** 当你发现自己的才华撑不起野心时&#xff0c;就请安静下来学习吧&#xff01;***************

Consul 服务注册与服务发现

1. 服务注册 对 Consul 进行服务注册之前&#xff0c;需要先部署一个服务站点&#xff0c;我们可以使用 ASP.NET Core 创建 Web 应用程序&#xff0c;并且部署到 Ubuntu 服务器上。 ASP.NET Core Hell World 应用程序示例代码&#xff0c;只需要三个文件&#xff0c;Startup.cs…