一、什么是图
说到图,不得不想到数学中“图”,让我们来看看维基百科怎么描述的吧:
在li'san'shu'x中,图(Graph)是用于表示物体与物体之间存在某种关系的结构。数学抽象后的“物体”称作节点或顶点(英语:Vertex,node或point),节点间的相关关系则称作边。在描绘一张图的时候,通常用一组点或小圆圈表示节点,其间的边则使用直线或曲线。
图的其他术语,这里就不过多陈述了,感兴趣可以去搜搜看;
二、实现思路
实现得用合适的数据结构保存顶点和边;
顶点直接使用数组即可;
边的保存可以使用二维数组(邻接矩阵)、邻接表,二维数组就是0表示无边,1表示有边,但是可能因为0过多,导致浪费性能,这里我们选择邻接表;
邻接表我用的map也就是映射来实现的,key为顶点对应的字符串,value为包含边的数组;
map的实现,我往期文章里有哦;
我们用三种颜色来表示,某个顶点的状态:白色,未被访问;灰色,访问过,未被探索;黑色,访问过且探索过;
三、方法
addVertex,增加一个顶点
addEdge,增加一条边
toString,重写toString
breadthFirstSearch,BFC遍历(广度优先搜索),传入指定的第一个被遍历的节点,以及对各个节点处理的回调函数
breadthFirstSearch,DFC遍历(深度优先搜索),传入指定的第一个被遍历的节点,以及对各个节点处理的回调函数
BFC遍历我是基于队列实现的,所以引用了一下,以前写的队列,需要的可以去看看;
因为我用的require是基于commonJs规范的,所以要用node运行,或者换成ESmodule的引用;
四、具体实现
const Dictionay = require("./13_js封装字典.js");
const Queue = require("./02_js封装队列结构");
function Graph() {
// 属性
this.vertexes = [];
this.edges = new Dictionay();
// 方法
// 1.添加顶点
Graph.prototype.addVertex = function (v) {
this.vertexes.push(v);
this.edges.set(v, []);
};
// 2.添加边(无向图)
// 如果重复添加呢?
Graph.prototype.addEdge = function (v1, v2) {
this.edges.get(v1).push(v2);
this.edges.get(v2).push(v1);
};
// 3.tostring
Graph.prototype.toString = function () {
let resultString = "";
this.edges.keys().forEach((el) => {
resultString += `${el}=>${this.edges.get(el)}
`;
});
return resultString;
};
// 4.重置颜色
Graph.prototype.initializeColor = function () {
let colors = [];
for (let i = 0; i < this.vertexes.length; i++) {
colors[this.vertexes[i]] = "white";
}
return colors;
};
// 5.BFS
Graph.prototype.breadthFirstSearch = function (fristV, handler) {
// 初始化颜色
let colors = this.initializeColor();
// 创建队列
let queue = new Queue();
queue.enqueue(fristV);
while (!queue.isEmpty()) {
let v = queue.dequeue();
let vList = this.edges.get(v);
vList.forEach((item) => {
if (colors[item] == "white") {
queue.enqueue(item);
colors[item] = "gray";
}
});
// 操作顶点
handler(v);
colors[v] = "black";
}
};
// 深度优先
Graph.prototype.depthFirstSearch = function (initV, handler) {
let colors = this.initializeColor();
this.dfsVisit(initV, colors, handler);
};
Graph.prototype.dfsVisit = function (v, colors, handler) {
colors[v] = "gray";
handler(v);
// 访问相连的顶点
let vList = this.edges.get(v);
vList.forEach((item) => {
if (colors[item] == "white") {
this.dfsVisit(item, colors, handler);
}
});
// 探索完变黑
colors[v] = "black";
};
}