通过学习图的搜索算法,我们来学习下两种常见的算法:BFS、DFS。

广度优先搜索(BFS)

广度优先搜索(Breadth-First-Search),它更像是一种地毯式、层层推进的搜索策略。先从距离起始点最近的顶点开始,然后以“水波纹”一样往外扩散。

代码实现

假设图的结构如下:

/*** 字典*/
class Dictionary {constructor() {this.items = {}}// 向字典添加新的元素set(key, value) {this.items[key] = value}// 通过键值从字典移除键值对应元素delete(key) {if (this.has(key)) {delete this.items[key]return true}return false}// 判断某个键值是否存在字典中has(key) {return key in this.items}// 通过键值查找对应值get(key) {return this.has(key) ? this.items[key] : undefined}// 清空字典clear() {this.items = {}}// 返回字典所包含元素的数量size() {return Object.keys(this.items).length}// 将字典所包含所有键名以数组形式返回keys() {return Object.keys(this.items)}// 将字典所包含所有键名对应值以数组形式返回values() {const values = []for (let k in this.items) {if (this.has(k)) {values.push(this.items[k])}}return values}getItems() {return this.items}
}class Queue {constructor() {this.items = []}// 入队enqueue(element) {this.items.push(element)}// 出队dequeue() {return this.items.shift()}// 获取队列第一个元素front() {return this.items[0]}// 是否为空isEmpty() {return !this.items.length}// 返回队列元素个数size() {return this.items.length}print() {console.log(this.items.toString())}
}/*** 图*/
class Graph {constructor() {// 存储顶点的值this.vertices = []// 散列表this.adjList = new Dictionary()}// 添加一个顶点addVertex(v) {this.vertices.push(v)// 初始化顶点的边this.adjList.set(v, [])}// 添加一个边addEdge(v, w) {// 这里是一个无向图this.adjList.get(v).push(w)if (!this.adjList.get(w)) {this.adjList.set(w, [])}this.adjList.get(w).push(v)}toString() {let s = ""for (let i = 0; i < this.vertices.length; i++) {s += this.vertices[i] + "->"const neighbors = this.adjList.get(this.vertices[i])for (let j = 0; j < neighbors.length; j++) {s += neighbors[j] + " "}s += "n"}return s}/*** 白色:表示该顶点还没有被访问* 灰色:表示该顶点被访问过,但是并未搜索过* 黑色:表示该顶点被访问过且完全搜索过*/initializeColor() {let color = []for (let i = 0; i < this.vertices.length; i++) {color[(this, this.vertices[i])] = "white"}return color}/*** 广度优先通过把顶点存入队列中,最先入队的顶点最先被搜索* @param {*} v 起始顶点* @param {*} callback cb*/bfs(v, callback) {const color = this.initializeColor()const queue = new Queue()// 起始点先入队queue.enqueue(v)while (!queue.isEmpty()) {// 出队const u = queue.dequeue()// 访问相邻的顶点[领接表]const neighbors = this.adjList.get(u)color[u] = "grey"for (let i = 0; i < neighbors.length; i++) {const w = neighbors[i]if (color[w] === "white") {color[w] = "grey"queue.enqueue(w)}}color[u] = "black"if (callback) {callback(u)}}}printNode(value) {console.log(`Visited vertex ${value}`)}
}// test case
const graph = new Graph()
const myVertices = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
for (let i = 0; i < myVertices.length; i++) {graph.addVertex(myVertices[i])
}
graph.addEdge("A", "B")
graph.addEdge("A", "C")
graph.addEdge("A", "D")
graph.addEdge("C", "D")
graph.addEdge("C", "G")
graph.addEdge("D", "G")
graph.addEdge("D", "H")
graph.addEdge("B", "E")
graph.addEdge("B", "F")
graph.addEdge("E", "I")
console.log(graph.toString())
graph.bfs(myVertices[0], graph.printNode)

上图我们只是通过按照BFS的方式来打印出图中顶点的访问顺序,下面我们可以做点实际的算法,比如给定一个图G、以及起始顶点v,找出图中其他顶点与v的最短距离【以边的数量统计】。

最短路径问题

...
/*** 广度优先通过把顶点存入队列中,最先入队的顶点最先被搜索* @param {*} v 起始顶点* @param {*} callback cb*/
bfs(v, callback) {const color = this.initializeColor()const queue = new Queue()// 记录起始顶点到其他顶点距离const distance = []// 存储前溯顶点,记录搜索路径// pred[w] 存储的是w是从哪个前驱顶点遍历过来的const pred = []// 起始点先入队queue.enqueue(v)// 初始化起始顶点到其他顶点距离for (let j = 0; j < this.vertices.length; j++) {distance[this.vertices[j]] = 0pred[this.vertices[j]] = null}while (!queue.isEmpty()) {// 出队const u = queue.dequeue()// 访问相邻的顶点[领接表]const neighbors = this.adjList.get(u)color[u] = "grey"for (let i = 0; i < neighbors.length; i++) {const w = neighbors[i]if (color[w] === "white") {color[w] = "grey"// 设置w与u的距离,这里是+1。// 如果是加权图,即为边的权值distance[w] = distance[u] + 1// 记录w顶点是从u顶点遍历而来pred[w] = uqueue.enqueue(w)}}color[u] = "black"if (callback) {callback(u)}}return {distance,pred,}
}

通过前溯顶点数组,我们可以拼接出从顶点A到其他顶点的具体路径。

bfsVertexPath(callback) {const path = {}const fromVertex = this.vertices[0]const { pred } = this.bfs(fromVertex, callback)        for (let i = 1; i < this.vertices.length; i++) {let curVertex = this.vertices[i]let startKey = curVertexpath[curVertex] = [curVertex]while (pred[startKey]) {path[curVertex].push(pred[startKey])startKey = pred[startKey]}}return path}

广度优先搜索_快速入门广度优先搜索相关推荐

  1. 【初码干货】使用阿里云开放搜索服务快速搭建资源搜索网站

    大家好,我又来了,答应云栖论坛一周一篇文章, 由于工作太忙已中断1个多月实在抱歉,这一次写点轻松有趣的东西-快速的做个资源搜索站 依稀记得十来年前,带宽还只有2M的时候,受各个论坛启发,做了可以搜索嘿 ...

  2. 广度优先搜索_计算机入门必备算法——广度优先遍历搜索

    1.  序言 又很久没有学习了,上次学到哈希表又称散列表的相关知识,这次我们学习一种新的数据结构来建立网络模型.这种数据结构被称作图.首先,我们先应该先了解一下什么是图,其次学习第一种图的算法,这种图 ...

  3. lucene 搜索_使用Lucene的搜索服务器搜索Jira问题

    lucene 搜索 您可能还记得我的第一篇博客文章 ,该文章描述了Lucene开发人员如何使用Lucene搜索应用程序查找我们的Jira问题来食用我们自己的狗粮. 该应用程序已成为许多现代Lucene ...

  4. 运动控制器编程_快速入门 | 篇二十一:运动控制器ZHMI组态编程简介一

    点击上方"正运动小助手",随时关注新动态! 运动控制器ZHMI组态编程简介一  今天我们来学习一下,运动控制器的ZHMI组态编程简介.本文主要从产品概述.控制器连接触摸屏使用.HM ...

  5. java azure blob 查询_快速入门:适用于 Java 的 Azure Blob 存储客户端库 v8 | Microsoft Docs...

    您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn. 快速入门:使用 Jav ...

  6. [XML-Jsoup]Jsoup_解析_快速入门

    xml常见的解析器: 1. JAXP:sun公司提供的解析器,支持dom和sax两种思想2. DOM4J:一款非常优秀的解析器3. Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析 ...

  7. 前端_快速入门Vue.js框架

    文章目录 快速入门Vue.js框架 0.前言 1.Vue.js框架 1.1.Vue简介 1.2.第一个Vue程序 1.3.el:挂载点 2.Vue指令 2.2.v-html 2.3.v-on 2.4. ...

  8. java redis快速入门_快速入门Redis系列(3)——Redis的JavaAPI操作(附带练习)

    作为快速入门Redis系列的第三篇博客,本篇为大家带来的是Redis的JavaAPI操作. 码字不易,先赞后看! Redis的JavaAPI操作 看完了上一篇博客,相信大家对于Redis的数据类型有了 ...

  9. java akka 教程_快速入门 Akka Java 指南

    快速入门 Akka Java 指南 Akka 是一个用于在 JVM 上构建高并发.分布式和容错的事件驱动应用程序的运行时工具包.Akka 既可以用于 Java,也可以用于 Scala.本指南通过描述 ...

最新文章

  1. 在一个数组中找 差值最大的两个数 差值最小的两个数 推广到 点对
  2. [转]SQL,LINQ,Lambda语法对照图
  3. springboot+jwt实现token登陆权限认证
  4. ios Sqlite数据库增删改查基本操作
  5. hdu-5063 Operation the Sequence
  6. IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列
  7. 使用bootstrap按钮组并设置其按钮组中按钮的尺寸和距离
  8. html怎么把一段文字设置为连接到下一个网页的按钮,网页设计三合一模拟试题(一)...
  9. 修改el-popover和el-select样式
  10. 入侵本地Mac OS X方针与技巧
  11. C语言求组合数取模,C 习题1.pdf
  12. ApiPost自动化测试基础之:接口参数依赖的情景处理...
  13. c# 调用jtts_Java与C#开发上的一些差异与转换方法
  14. python面试题:python计算股票收益最大化
  15. 程序化交易高手的交易心得 分享~
  16. 申报2021国家高新技术企业认定,有哪些标准?
  17. HEKA.FitMaster.v2.15(用来分析和测试那些通过Patchmaster或Pulse得
  18. 阿里巴巴icon在vue项目中使用方法
  19. PCAT 点云标注软件
  20. JavaScript学习(七)——对象与数组、内部对象(1)

热门文章

  1. day1 java的规范以及变量与数据类型
  2. java String对象转Base64
  3. python 之禅_Python 之禅
  4. java按键修改_修改键位映射,打造自己的个性键盘 [转自赵翔鹏的Blog]
  5. python 归一化_数据的标准化和归一化
  6. so库调用java函数_linux下so动态库调用主程序函数
  7. 使用jsp实现word excel格式报表打印-JSP教程 Jsp/Servlet
  8. 如何让CentOS8虚拟机与主机相互Ping通
  9. Python案例:两种方法实现词频统计
  10. css专业名词,CSS进阶系列一(flex布局基础知识——介绍、规范、主要思想、专业术语)...