Javascript 在树结构中查找所有唯一路径
假设我有一个文本文件中的目录结构Javascript 在树结构中查找所有唯一路径,javascript,node.js,algorithm,Javascript,Node.js,Algorithm,假设我有一个文本文件中的目录结构 root1 child1 child2 grandchild1 grandchild2 child3 root2 child1 child2 grandchild1 greatgrandchild1 如何将上述树结构转换为如下所示的嵌套数组: [ [ "root1", "child1" ], [ "root1", "child2",
root1
child1
child2
grandchild1
grandchild2
child3
root2
child1
child2
grandchild1
greatgrandchild1
如何将上述树结构转换为如下所示的嵌套数组:
[
[ "root1", "child1" ],
[ "root1", "child2", "grandchild1" ],
[ "root1", "child2", "grandchild2" ],
[ "root1", "child3" ],
[ "root2", "child1" ],
[ "root2", "child2", "grandchild1", "greatgrandchild1" ]
]
编辑
var fs = require("fs");
var treeGrapher = require("./lib/treeGrapher.js");
var uniquePaths = require("./lib/uniquePaths.js");
var tmpl = fs.readFileSync("./director.tmpl.txt", "utf8");
var graphs = treeGrapher(tmpl); //returns an array of trees
var paths = arrange(graphs);
/**
[
[ "root1", "rootchild1" ],
[ "root1", "child2", "gc1" ],
[ "root2" ],
[ "root3", "root3-child1" ]
]
*/
function arrange(trees) {
var bucket = [];
trees.forEach(function(list) {
uniquePaths(list).forEach(function(arr) {
bucket.push(arr);
});
});
return bucket;
}
越走越远,但递归遍历树时仍然存在问题
var $text = ''
+ 'root1\n'
+ ' r1 child1\n'
+ ' r1 child2\n'
+ ' r1 grandchild1\n'
+ ' r1 grandchild2\n'
+ ' r1 child3\n'
+ 'root2\n'
+ ' r2 child1\n'
+ ' r2 c1\n'
+ ' r2 c1 g1\n'
+ ' r2 child2\n'
+ ' r2 grandchild1\n'
+ ' r2 greatgrandchild1\n'
+ 'test!\n'
+ 'root3\n'
+ ' r3 child1\n'
+ ' r3 c1\n'
+ ' r3 c1 g1\n'
+ ' r3 child3\n'
+ ' r3 grandchild1\n'
+ ' r3 greatgrandchild1';
var dirGen = (function(trees) {
"use strict";
var indent = /[\s\t]/g;
var lTrim = /[\s\t]*/;
var $trees = decompose(trees);
var $root = [];
function init() {
var paths = $trees.map(treeMap)
$test(paths);
}
function treeMap(tree, n, arr) {
var base = new LinkedList();
return bfs(-1, tree, base);
}
function bfs(n, tree, base) {
var l, t;
n++;
//base case
if (n === tree.length) return trails(base);
l = tree.length;
t = tree[n];
var cur = { label: t.replace(lTrim, ""), depth: depth(t), children: [] };
//set root
if (n === 0) {
base.tree = cur;
return bfs(n, tree, base);
}
base.push(cur);
return bfs(n, tree, base);
}
function depth(str) {
var d = str.match(indent);
if (d === null) return 0;
return d.length;
}
function trails(arr) {
return arr;
}
function LinkedList() {}
LinkedList.prototype.push = function(node) {
var l = this.tree.children.length;
var j = l - 1;
if (l === 0) {
this.tree.children.push(node);
return;
}
//walk through children array in reverse to get parent
while (j > -1) {
var d = this.tree.children[j].depth;
//child
if (node.depth > d) {
console.log(this.tree.children[j], node)
return this.tree.children[j].children.push(node);
}
//sibling
if (node.depth === d) {
}
j--;
}
}
function decompose(arr) {
var treeBreak = /[\r\n](?=\w)/gm;
var lines = /[\r\n]+(?!\s)*/g;
return arr.split(treeBreak).map(function(str) {
return str.split(lines)
});
}
function $test(str) {
var json = JSON.stringify(str, null, 2);
var wtf = "<pre>" + json + "</pre>";
document.write(wtf);
}
return init;
})($text);
dirGen();
var$text=''
+“root1\n”
+'r1 child1\n'
+'r1 child2\n'
+'r1\n'
+“r1-2\n”
+'r1 child3\n'
+“root2\n”
+“r2儿童1\n”
+“r2 c1\n”
+“r2 c1 g1\n”
+“r2儿童2\n”
+“1\n”
+“r2曾孙1\n”
+“测试\不
+“root3\n”
+“r3儿童1\n”
+“r3 c1\n”
+“r3 c1 g1\n”
+“r3儿童3\n”
+“r3-1\n”
+“r3曾孙1”;
var dirGen=(函数(树){
“严格使用”;
var indent=/[\s\t]/g;
var lTrim=/[\s\t]*/;
var$trees=分解(树);
var$root=[];
函数init(){
变量路径=$trees.map(treeMap)
$test(路径);
}
函数树映射(树,n,arr){
var base=newlinkedlist();
返回bfs(-1,树,基);
}
函数bfs(n,树,基){
变量l,t;
n++;
//基本情况
如果(n==树长)返回路径(基);
l=树的长度;
t=树[n];
var cur={label:t.replace(lTrim,“”),depth:depth(t),children:[]};
//扎根
如果(n==0){
base.tree=cur;
返回bfs(n,树,基);
}
基推(cur);
返回bfs(n,树,基);
}
功能深度(str){
var d=str.match(缩进);
如果(d==null)返回0;
返回d.length;
}
功能跟踪(arr){
返回arr;
}
函数LinkedList(){}
LinkedList.prototype.push=函数(节点){
var l=this.tree.children.length;
var j=l-1;
如果(l==0){
this.tree.children.push(节点);
返回;
}
//反向遍历子数组以获取父数组
而(j>-1){
var d=this.tree.children[j].depth;
//孩子
如果(node.depth>d){
console.log(this.tree.children[j],节点)
返回此.tree.children[j].children.push(节点);
}
//兄弟姐妹
如果(node.depth==d){
}
j--;
}
}
功能分解(arr){
var treeBreak=/[\r\n](?=\w)/gm;
变量行=/[\r\n]+(?!\s)*/g;
返回arr.split(treeBreak).map(函数(str){
返回str.split(行)
});
}
功能$test(str){
var json=json.stringify(str,null,2);
var wtf=”“+json+”;
function populateTree (tree, text) {
var rTab, rChunks, rChunk;
var chunks, chunk;
var i, l, node;
if (!text) return;
rTab = /^\s{4}/gm;
rChunks = /[\r\n]+(?!\s{4})/g;
rChunk = /^(.+)(?:[\r\n]+((?:\r|\n|.)+))?$/;
chunks = text.split(rChunks);
l = chunks.length;
for (i = 0; i < l; i++) {
chunk = chunks[i].match(rChunk);
node = { label: chunk[1], children: [] };
tree.children.push(node);
populateTree(node, chunk[2] && chunk[2].replace(rTab, ''));
}
}
function printTree(tree, prefix) {
var i, l = tree.children.length;
for (i = 0; i < l; i++) {
console.log(prefix + tree.children[i].label);
printTree(tree.children[i], prefix + ' ');
}
}
文件编写(wtf);
}
返回init;
})($文本);
dirGen();
到目前为止,代码为我提供了这个json数组:
我懒得读你的算法:-|
var tree = { children: [] };
populateTree(tree, text);
printTree(tree, '');
我不熟悉Nodejs,我只能说它在Chrome中使用以下字符串:
var treeGrapher = (function() {
"use strict";
var find = require("lodash.find");
var indent = /[\s\t]/g;
var lTrim = /[\s\t]*/;
var treeBreak = /[\r\n](?=\w)/gm;
var lines = /[^\r\n]+/g
function init(text) {
return decompose(text).map(function(tree) {
return populate(-1, tree, {})
});
}
function depth(str) {
var d = str.match(indent);
if (d === null) return 0;
return d.length;
}
function decompose(txt) {
return txt.split(treeBreak).map(function(str) {
return str.match(lines);
});
}
function populate(n, tree, root, cache, breadCrumbs) {
var branch, leaf, crumb;
//set index
n++;
//root case
if (n === tree.length) return root.tree;
branch = tree[n];
leaf = { label: branch.replace(lTrim, ""), index: n, depth: depth(branch), children: [] };
breadCrumbs = breadCrumbs || [];
crumb = cache ? { label: cache.label, index: cache.index, depth: cache.depth, node: cache } : undefined;
//set root
if (n === 0) {
root.tree = leaf;
return populate(n, tree, root, leaf, breadCrumbs);
}
//push child to cached parent from previous iteration
if (leaf.depth > cache.depth) {
cache.children.push(leaf);
root.parent = cache;
breadCrumbs.push(crumb)
return populate(n, tree, root, leaf, breadCrumbs);
}
//push child to distant parent via breadcrumb search
if (leaf.depth <= cache.depth) {
var rev = breadCrumbs.slice(0).reverse();
var parentNode = find(rev, function(obj){ return obj.depth < leaf.depth }).node;
parentNode.children.push(leaf);
return populate(n, tree, root, leaf, breadCrumbs);
}
}
return init;
})();
module.exports = treeGrapher;
(回答我自己的问题)
好的,所以实现实际上有三个部分:(1)将文本文件转换为树结构,然后(2)在树上使用dfs查找唯一路径,最后(3)将所有路径合并到单个数组中
首先,文本到树的转换器。您仍然需要找到每个项目的深度(缩进级别),因为这决定了它是子项目还是同级项目:
var uniquePaths = (function() {
"use strict";
function init(tree) {
return walk(tree, [], []);
}
function walk(branch, path, basket) {
var fork = path.slice(0);
var i = 0;
var chld = branch.children;
var len = chld.length;
fork.push(branch.label);
if (len === 0) {
basket.push(fork);
return basket;
}
for (i; i < len; i++) walk(chld[i], fork, basket);
return basket;
}
return init;
})();
module.exports = uniquePaths;
main.js
新结构的用途是什么?似乎可以对其进行改进,使其对递归循环更加友好。还有,是什么生成了文本文件?如果这是一个脚本,你可以访问你可能会杀死2鸟一个stone@charlietfl目标是拥有一个npm模块,当您初始化它时,它将查找目录模板,并通过加入算法生成的每个唯一路径数组的索引,自动
mkdirp
目录结构。如果这样做,为什么要写入文本文件?如果您不同时写入数组,并使嵌套数组更像一个传统的树结构,在每个级别上都有相同的子节点数组名称,这是没有意义的。可能我解释得不够好;模块使用fs.readFileSync
搜索包含要使用的目录结构的文本文件。到目前为止,我编写的代码将文本文件转换为需要用于fs.mkdirp(target,callback)
的数据,例如:var uniquePath=[“root1”、“child1”、“孙子1”];mkdirp(uniquePath.join(“/”),函数(err,res){//directory created})代码>查找此问题的两种通用算法是深度优先遍历和广度优先遍历。首先,这非常有用:)
root1
child1
child2
gc1
root2
root3
root3-child1
var fs = require("fs");
var treeGrapher = require("./lib/treeGrapher.js");
var uniquePaths = require("./lib/uniquePaths.js");
var tmpl = fs.readFileSync("./director.tmpl.txt", "utf8");
var graphs = treeGrapher(tmpl); //returns an array of trees
var paths = arrange(graphs);
/**
[
[ "root1", "rootchild1" ],
[ "root1", "child2", "gc1" ],
[ "root2" ],
[ "root3", "root3-child1" ]
]
*/
function arrange(trees) {
var bucket = [];
trees.forEach(function(list) {
uniquePaths(list).forEach(function(arr) {
bucket.push(arr);
});
});
return bucket;
}