1.概念
图结构是一种非线性的数据结构。是一些顶点的集合,这些顶点通过一系列边连接。顶点用圆圈表示,边就是这些圆圈之间的连线。
生活中基于图的现象有:复杂的网络结构,人与人之间的人际关系等。如下图所示。
2.封装图结构
function Graph() { // 属性 this.vertexes = [] // 存储顶点 this.adjList = new Dictionay() // 存储边 // 方法 Graph.prototype.addVertex = function (v) { //添加顶点 this.vertexes.push(v) this.adjList.set(v, []) } Graph.prototype.addEdge = function (v, w) { //添加边 this.adjList.get(v).push(w) this.adjList.get(w).push(v) } Graph.prototype.toString = function () { var resultStr = "" for (var i = 0; i < this.vertexes.length; i++) { resultStr += this.vertexes[i] + "->" var adj = this.adjList.get(this.vertexes[i]) for (var j = 0; j < adj.length; j++) { resultStr += adj[j] + " " } resultStr += "\n" } return resultStr } Graph.prototype.initializeColor = function () { var colors = [] for (var i = 0; i < this.vertexes.length; i++) { colors[this.vertexes[i]] = "white" } return colors } // 广度优先算法 Graph.prototype.bfs = function (v, handler) { // 1.初始化颜色 var color = this.initializeColor() // 2.创建队列 var queue = new Queue() // 3.将传入的顶点放入队列中 queue.enqueue(v) // 4.从队列中依次取出和放入数据 while (!queue.isEmpty()) { // 4.1.从队列中取出数据 var qv = queue.dequeue() // 4.2.获取qv相邻的所有顶点 var qAdj = this.adjList.get(qv) // 4.3.将qv的颜色设置成灰色 color[qv] = "gray" // 4.4.将qAdj的所有顶点依次压入队列中 for (var i = 0; i < qAdj.length; i++) { var a = qAdj[i] if (color[a] === "white") { color[a] = "gray" queue.enqueue(a) } } // 4.5.因为qv已经探测完毕, 将qv设置成黑色 color[qv] = "black" // 4.6.处理qv if (handler) { handler(qv) } } } // 深度优先搜索 Graph.prototype.dfs = function (handler) { // 1.初始化颜色 var color = this.initializeColor() // 2.遍历所有的顶点, 开始访问 for (var i = 0; i < this.vertexes.length; i++) { if (color[this.vertexes[i]] === "white") { this.dfsVisit(this.vertexes[i], color, handler) } } } // dfs的递归调用方法 Graph.prototype.dfsVisit = function (u, color, handler) { // 1.将u的颜色设置为灰色 color[u] = "gray" // 2.处理u顶点 if (handler) { handler(u) } // 3.u的所有邻接顶点的访问 var uAdj = this.adjList.get(u) for (var i = 0; i < uAdj.length; i++) { var w = uAdj[i] if (color[w] === "white") { this.dfsVisit(w, color, handler) } } // 4.将u设置为黑色 color[u] = "black" } } // 创建字典的构造函数 function Dictionay() { // 字典属性 this.items = {} // 在字典中添加键值对 Dictionay.prototype.set = function (key, value) { this.items[key] = value } // 判断字典中是否有某个key Dictionay.prototype.has = function (key) { return this.items.hasOwnProperty(key) } // 从字典中移除元素 Dictionay.prototype.remove = function (key) { // 1.判断字典中是否有这个key if (!this.has(key)) return false // 2.从字典中删除key delete this.items[key] return true } // 根据key去获取value Dictionay.prototype.get = function (key) { return this.has(key) ? this.items[key] : undefined } // 获取所有的keys Dictionay.prototype.keys = function () { return Object.keys(this.items) } // 获取所有的value Dictionay.prototype.values = function () { return Object.values(this.items) } // size方法 Dictionay.prototype.size = function () { return this.keys().length } // clear方法 Dictionay.prototype.clear = function () { this.items = {} } } // 创建队列的构造函数 function Queue() { var items = [] // 队列操作的方法 // enter queue方法 this.enqueue = function (element) { items.push(element) } // delete queue方法 this.dequeue = function () { return items.shift() } // 查看前端的元素 this.front = function () { return items[0] } // 查看队列是否为空 this.isEmpty = function () { return items.length === 0 } // 查看队列中元素的个数 this.size = function () { return items.length } }
// 测试 var graph = new Graph() var myVertexes = ["A", "B", "C", "D", "E", "F", "G", "H", "I"] for (var i = 0; i < myVertexes.length; i++) { graph.addVertex(myVertexes[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()) // 调用广度优先算法 var result = "" graph.bfs(graph.vertexes[0], function (v) { result += v + " " }) console.log(result) // A B C D E F G H I // 调用深度优先算法 var result2 = "" graph.dfs(function (v) { result2 += v + " " }) console.log(result2) // A B E I F C D G H //A->B C D //B->A E F //C->A D G //D->A C G H //E->B I //F->B //G->C D //H->D //I->E