diff --git a/b00-阅读笔记/学习js数据结构与算法/graph.js b/b00-阅读笔记/学习js数据结构与算法/graph.js new file mode 100644 index 0000000..9ba4989 --- /dev/null +++ b/b00-阅读笔记/学习js数据结构与算法/graph.js @@ -0,0 +1,102 @@ +function Graph() { + this.vertices = []; + this.vertexMap = new Map(); + this.adjList = new Map(); + this.addVertex = function(v) { + return this.vertexMap.has(v.id) ? null : (v.status = 0, this.vertexMap.set(v.id, v), this.vertices.push(v),this.adjList.set(v.id, new Set()), v); + }; + this.addEdge = function(sourceId, targetId) { + if (this.vertexMap.has(sourceId) && this.vertexMap.has(targetId)) { + this.adjList.get(sourceId).add(this.vertexMap.get(targetId)); + this.adjList.get(targetId).add(this.vertexMap.get(sourceId)); + } + return this; + }; + this.getVertex = function(id) { + return this.vertexMap.get(id); + }; + this.getVertexAdj = function(id) { + return this.adjList.get(id) || []; + }; + this.toString = function() { + this.adjList.forEach((value, key) => { + console.log(key + ':' + Array.from(value).map(e => e.id).join(',') + '\n'); + }); + }; +} + +function BFS(graph, root, callback) { + var queue = []; + if (root == null) return null; + root.status = 1 && queue.push(root); + while(queue.length) { + var curVertex = queue.shift(); + // 将相邻节点入队 + var adjVertexs = graph.getVertexAdj(curVertex.id); + adjVertexs.forEach(e => { + // 忽略已经入队或已经被访问过的节点 + if (e.status === 0) { + e.status = 1 && queue.push(e); + } + }); + // 节点被访问 + callback(curVertex); + curVertex.status = 2; + } +} + +function DFS(graph, callback) { + var stack = []; + var vertexs = graph.vertices; + // 遍历每个节点,若节点未被访问,则入栈 + // 若栈非空,出栈 + // 继续遍历其相邻未被访问的子节点 + for (var i = 0, length = vertexs.length; i < length; i++) { + if (vertexs[i].status === 0) { + vertexs[i].status = 1; + stack.push(vertexs[i]); + while(stack.length) { + var v = stack.pop(); + v.status = 2; + callback(v); + var adjVertexs = graph.getVertexAdj(v.id); + adjVertexs.forEach(e => { + if (e.status === 0) { + e.status = 1; + stack.push(e); + } + }); + } + } + } +} + +var graph = new Graph(); +graph.addVertex({id: 'A'}); +graph.addVertex({id: 'B'}); +graph.addVertex({id: 'C'}); +graph.addVertex({id: 'D'}); +graph.addVertex({id: 'E'}); +graph.addVertex({id: 'F'}); +graph.addVertex({id: 'G'}); +graph.addVertex({id: 'H'}); +graph.addVertex({id: 'I'}); +graph.addEdge('A', 'B'); +graph.addEdge('A', 'C'); +graph.addEdge('A', 'D'); +graph.addEdge('B', 'E'); +graph.addEdge('B', 'F'); +graph.addEdge('C', 'D'); +graph.addEdge('C', 'G'); +graph.addEdge('D', 'G'); +graph.addEdge('D', 'H'); +graph.addEdge('E', 'I'); + +// console.log('BFS:\n'); +// BFS(graph, graph.getVertex('A'), e => { +// console.log(e.id); +// }); +console.log('DFS:\n'); +DFS(graph, e => { + console.log(e.id); +}); \ No newline at end of file diff --git a/b00-阅读笔记/学习js数据结构与算法/index.html b/b00-阅读笔记/学习js数据结构与算法/index.html new file mode 100644 index 0000000..d8795a8 --- /dev/null +++ b/b00-阅读笔记/学习js数据结构与算法/index.html @@ -0,0 +1,13 @@ + + + + + + + test + + + + + + \ No newline at end of file diff --git a/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.js b/b00-阅读笔记/学习js数据结构与算法/tree.js similarity index 99% rename from b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.js rename to b00-阅读笔记/学习js数据结构与算法/tree.js index fea7617..7699989 100644 --- a/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.js +++ b/b00-阅读笔记/学习js数据结构与算法/tree.js @@ -100,4 +100,4 @@ var root = { } } }; -removeNode(root, 15); \ No newline at end of file +removeNode(root, 15); diff --git a/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.md b/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.md index 5cf3060..5e1abb2 100644 --- a/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.md +++ b/b00-阅读笔记/学习js数据结构与算法/学习js数据结构与算法.md @@ -388,7 +388,7 @@ function Graph() { this.vertexMap = new Map(); this.adjList = new Map(); this.addVertex = function(v) { - return this.vertexMap.has(v.id) ? null : (this.vertexMap.set(v.id, v),this.vertices.push(v),this.adjList.set(v.id, new Set()), v); + return this.vertexMap.has(v.id) ? null : (v.status = 0, this.vertexMap.set(v.id, v), this.vertices.push(v),this.adjList.set(v.id, new Set()), v); }; this.addEdge = function(sourceId, targetId) { if (this.vertexMap.has(sourceId) && this.vertexMap.has(targetId)) { @@ -397,6 +397,12 @@ function Graph() { } return this; }; + this.getVertex = function(id) { + return this.vertexMap.get(id); + }; + this.getVertexAdj = function(id) { + return this.adjList.get(id) || []; + }; this.toString = function() { this.adjList.forEach((value, key) => { console.log(key + ':' + Array.from(value).map(e => e.id).join(',') + '\n'); @@ -407,8 +413,50 @@ function Graph() { ### 图的遍历 -* 广度优先(BFS):用**栈**实现。 -* 深度优先(DFS):用**队列**实现 +* 广度优先(BFS):用**队列**实现。 +* 深度优先(DFS):用**栈**实现。 + +用 status 表示节点状态: + +* 0 - 初始状态 +* 1 - 被探索状态 +* 2 - 被访问过状态 + +```js +// 广度优先(BFS)算法:用**队列**实现。 +/* +1. 创建一个队列 Q +2. 将 v 标记为 1,并入队 +3. 如果 Q 非空,重复以下步骤 + 3.1 将 u 出队 + 3.2 寻找 u 的相邻节点,并将未被访问的节点入栈,并标记为 1 + 3.3 访问节点,标记为 2 +*/ +function BFS(root, callback) { + var queue = []; + if (root == null) return null; + root.status = 1 && queue.push(root); + while(queue.length) { + var curVertex = queue.shift(); + // 将相邻节点入队 + var adjVertexs = graph.getVertexAdj(curVertex.id); + adjVertexs.forEach(e => { + // 忽略已经入队或已经被访问过的节点 + if (e.status === 0) { + e.status = 1 && queue.push(e); + } + }); + // 节点被访问 + callback(curVertex); + curVertex.status = 2; + } +} +``` + +```js +// 深度优先(DFS)算法:用**栈**实现。 +function DFS(callback) {} +``` ## 排序和搜索算法