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

复习 深度优先搜索和广度优先搜索(js)

先来了解一下图的存储方式------领接表和领接矩阵

无向图的领接矩阵和领接表
在这里插入图片描述
有向图的领接矩阵和领接表

在这里插入图片描述
知道图是如何存储的以后,就可以用代码来保存一个图,采用邻接表的方式来存储图

function Chart() {
  /*
  顶点
   */
  this.vertex = []

  /*
  边
   */
  this.edge = new Map()

//  添加顶点
  Chart.prototype.addVertex = (vertex) => {
    this.vertex.push(vertex)
    this.edge.set(vertex, [])
  }

//  添加边(无向图)
  Chart.prototype.addEdge = (vertex1, vertex2) => {
    this.edge.set(vertex1, [...this.edge.get(vertex1), vertex2])
    this.edge.set(vertex2, [...this.edge.get(vertex2), vertex1])
  }

接下来就来看看图的两种遍历方式

广度优先搜索

在这里插入图片描述
在这里插入图片描述

深度优先搜索

在这里插入图片描述

完整代码:

// 队列,
function Queue() {
  this.data = []

  Queue.prototype.enqueue = (ele) => {
    this.data.push(ele)
  }

  Queue.prototype.dequeue = () => {
    return this.data.shift()
  }

  Queue.prototype.front = () => {
    return this.data[0]
  }

  Queue.prototype.isEmpty = () => {
    return this.data.length === 0
  }

  Queue.prototype.size = () => {
    return this.data.length
  }

  Queue.prototype.toString = () => {
    return this.data.join('')
  }
}

/*
采用邻接表表示法来封装 图结构
 */

function Chart() {
  /*
  顶点
   */
  this.vertex = []

  /*
  边
   */
  this.edge = new Map()

//  添加顶点
  Chart.prototype.addVertex = (vertex) => {
    this.vertex.push(vertex)
    this.edge.set(vertex, [])
  }

//  添加边(无向图)
  Chart.prototype.addEdge = (vertex1, vertex2) => {
    this.edge.set(vertex1, [...this.edge.get(vertex1), vertex2])
    this.edge.set(vertex2, [...this.edge.get(vertex2), vertex1])
  }

//  将所有顶点和边拼接字符串
  Chart.prototype.toString = () => {
    let str = ''
    this.vertex.forEach(item => {
      str += item + '--->'
      this.edge.get(item).forEach(current => {
        str += current
      })
      str += '\n'
    })
    return str
  }

//  记录每个节点的状态
  /**
   * 0:没有被访问过,
   * 1:被访问过
   */

  Chart.prototype.initStatus = () => {
    const status = []
    this.vertex.forEach(item => status[item] = 0)
    return status
  }

//  广度优先搜索 (类似于树结构中的 层级遍历)
  Chart.prototype.breadthFirstSearch = (firstVertex, handle) => {
    //  1. 声明一个队列
    const queue = new Queue()
    //  2. 插入选取得第一个节点
    queue.enqueue(firstVertex)
    const status = this.initStatus()
     //  3. 改变状态,此时状态变为 已访问
    status[firstVertex] = 1
    //  4. 遍历队列探索每个节点
    while (!queue.isEmpty()) {
      //  4.1 不为空探索队列的首元素,并移出队列,
      const v = queue.dequeue()
      //  4.2 获取顶点 v 的相邻顶点
      const adjacentVertex = this.edge.get(v)
      //  4.3 将这些 相邻顶点 插入到队列中
      adjacentVertex.forEach(item => {
        // 4.4 如果此顶点已在队列中就不再插入(在队列中状态为:访问过)
        if (status[item] === 0) {
          queue.enqueue(item)
          //  4.5 进入队列后,状态就变为: 访问过
          status[item] = 1
        }
      })
      //  5. 对顶点进行某些操作
      handle(v)
    }
  }

//  深度优先搜索(类似于树中的 先序遍历)
  Chart.prototype.depthFirstSearch = (firstVertex, handle) => {

    const searchTraversal = (vertex, handle, status) => {
      // 0. 如果此顶点已被访问,就不在对其进行访问探索操作了
      if (status[vertex] >= 1) return
      //  1. 状态改变,已被访问
      status[vertex] = 1
      //  2. 拿到相邻顶点,且是没有被访问过的相邻顶点
      const adjacentVertex = this.edge.get(vertex).filter(currentVertex => status[currentVertex] === 0)
      //  3. 进行我们需要的操作
      handle(vertex)
      //  5. 遍历相邻顶点
      adjacentVertex.forEach(item => {
        searchTraversal(item, handle, status)
      })
    }
    const status = this.initStatus()
    searchTraversal(firstVertex, handle, status)
  }
}
const chart = new Chart()
// 添加顶点
const vertex = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
vertex.forEach(item => chart.addVertex(item))
// 添加边
chart.addEdge('a', 'b')
chart.addEdge('a', 'c')
chart.addEdge('a', 'd')
chart.addEdge('c', 'd')
chart.addEdge('c', 'g')
chart.addEdge('d', 'g')
chart.addEdge('d', 'h')
chart.addEdge('b', 'e')
chart.addEdge('b', 'f')
chart.addEdge('e', 'i')
let str = ''
chart.breadthFirstSearch(chart.vertex[0], (v) => str += v + ' ')
console.log(str)
str = ''
chart.depthFirstSearch(chart.vertex[0], (v) => str += v + ' ')
console.log(str)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值