图搜索法(广、深度优先搜索)
应用语言JavaScript
构建一个图,结构如下:
首先写一个类,包含添加顶点和边的方法
图在JavaScript中的本质结构为:
{
A:["B"],
B:["A"],
...:[]
}
其中key代表顶点,数组代表连线,B:["A"]代表B与A相连,一般情况下A也会与B相连,为空时代表无连线
function Graph() {
this.vertexes = []; //顶点
this.edges = {
}; //边
// 添加顶点
Graph.prototype.addVertex = function (v) {
this.vertexes.push(v);
for (let i in this.vertexes) {
this.edges[this.vertexes[i]] = [];
}
}
// 添加边
Graph.prototype.addEdge = function (v1, v2) {
for (let i in this.edges) {
if (i === v1) {
this.edges[v1].push(v2);
}
if (i === v2) {
this.edges[v2].push(v1);
}
}
}
}
//new一个实例并添加顶点和连线
var graph = new Graph();
var myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','K'];
myVertexes.forEach(e => {
graph.addVertex(e);
})
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('A', 'D');
graph.addEdge('B', 'E');
graph.addEdge('B', 'F');
graph.addEdge('C', 'H');
graph.addEdge('D', 'I');
graph.addEdge('D', 'J');
graph.addEdge('E', 'K');
graph.addEdge('H', 'G');
graph.addEdge('J', 'L');
/*
最后得到的图为:
{
A: [ 'B', 'C', 'D' ],
B: [ 'A', 'E', 'F' ],
C: [ 'A', 'H' ],
D: [ 'A', 'I', 'J' ],
E: [ 'B', 'K' ],
F: [ 'B' ],
G: [ 'H' ],
H: [ 'C', 'G' ],
I: [ 'D' ],
J: [ 'D', 'L' ]
}
*/
广度优先搜索-BFS
假设我们一开始位于某个顶点(即起点),此时并不知道图的整体结构,而我们的目的是从起点开始顺着边搜索,直到到达指定顶点(即终点),在此过程中每走到一个顶点,就会判断一次它是否为终点,广度优先搜索会优先从离起点近的顶点开始搜索。
广度优先搜索的特征为从起点开始,由近及远进行广泛的搜索。因此,目标顶点离起点越近,搜索结束得就越快。
用JavaScript实现
Graph.prototype.BFS = function (target) {
// 被搜索过的顶点为 - 橙色
let orangeArray = [];
for (let i in this.edges) {
// 初始顶点
if (orangeArray.length === 0) {
orangeArray.push(i);
}
//候补顶点队列 - 绿色
let greenArray = Object.assign([], this.edges[i]);
for (let a = 0; a < this.edges[i].length; a++) {
// 取候补队列取第一个为顶点
let hbTopPoint = greenArray.shift();
// 防止重复添加
if (orangeArray.filter(e => e === hbTopPoint).length === 0) {
// 将已搜索的顶点添加到已搜索顶点数组
orangeArray.push(hbTopPoint)
// 如果到达目的地则停止搜索并返回已搜索的点,否则重复此过程
if (hbTopPoint === target) {
return orangeArray;
}
}
}
}
}
var BFSResult = graph.BFS("H");
console.log(BFSResult);
/*
[
'A', 'B', 'C',
'D', 'E', 'F',
'H'
]
*/
深度优先搜索-DFS
深度优先搜索会沿着一条路径不断往下搜索直到不能再继续为止,然后再折返,开始搜索下一条候补路径。
用JavaScript实现
Graph.prototype.DFS = function (target) {
//已搜索
let orangeArray = [];
// 是否找到目标点
let isResult = false;
/**
* 传入递归算法中一个顶点和候补点数组对其下所有顶点以及候补点进行深度搜索,
* 判断如果已搜索顶端数组中不存在当前顶点则将该顶点push进已搜索顶点数组
* 判断是否找到 如果找到则结束循环;
*/
for (let i in this.edges) {
if (isResult === true) {
return orangeArray;
}
if (orangeArray.filter(e => e === i).length === 0) {
orangeArray.push(i);
}
let greenArray = Object.assign([], this.edges[i]);
handler(i, greenArray);
}
/**
* 递归算法
* 拿到顶点和候补顶点数组
* for循环拿候补数组中的第一个作为新顶点
* 判定新顶点是否存在于被搜索点数组orangeArray中
* 如果不存在则添加新顶点到被搜索数组中,然后继续搜索新顶点下的候补数组
* 重复这个过程一直到当前顶点下没有候补数组(说明所有分支都以搜索结束)或找到为止
*/
let handler = (i, greenArray) => {
if (!this.edges[i]) {
return;
}
if (i === target) {
isResult = true;
return;
}
for (let a = 0; a < this.edges[i].length; a++) {
let topPoint = greenArray.shift();
if (orangeArray.filter(e => e === topPoint).length === 0) {
orangeArray.push(topPoint);
return handler(topPoint, Object.assign([], this.edges[topPoint]));
}
}
}
}
/*
[
'A', 'B', 'E',
'K', 'F', 'C',
'H'
]
*/
待续