复习 深度优先搜索和广度优先搜索(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)