我最近采访了Facebook的前端工程师职位。对于我的手机屏幕,我是以下问题:给定DOM树中的节点从相同的DOM树中找到相同位置的节点。为清晰起见,请参见下图。
A B
O O
|\ |\
O O O O
/|\ /|\
O O O O O O
\ \
O O
这是我的解决方案,我想知道我可以做些什么来改进/优化它。
var rootA, rootB;
function findNodeB(nodeA) {
// Variable to store path up the DOM tree
var travelPath = [];
// Method to travel up the DOM tree and store path to exact node
var establishPath = function(travelNode) {
// If we have reached the top level node we want to return
// otherwise we travel up another level on the tree
if (travelNode === rootA) {
return;
} else {
establishPath(travelNode.parentNode);
}
// We store the index of current child in our path
var index = travelNode.parentNode.childNodes.indexOf(travelNode);
travelPath.push(index);
}
var traverseTree = function(bTreeNode, path) {
if(path.length === 0) {
return bTreeNode;
} else {
traverseTree(bTreeNode.childNodes[path.pop()], path);
}
}
establishPath(rootB, nodeA);
return traverseTree(rootB, travelPath);
}
答案 0 :(得分:20)
由于至少Axel对迭代解决方案表现出兴趣,因此它是:
给定两个具有相同结构的树,以及第一个树中的指定节点,找到第二个树中具有相同位置的节点。
如果我们没有关于这两棵树的其他信息,那么每个节点的位置可以表征为从根节点开始的路径,其中路径中的每一步都被指定为childNode数组的索引。
function indexOf(arrLike, target) {
return Array.prototype.indexOf.call(arrLike, target);
}
// Given a node and a tree, extract the nodes path
function getPath(root, target) {
var current = target;
var path = [];
while(current !== root) {
path.unshift(indexOf(current.parentNode.childNodes, current));
current = current.parentNode;
}
return path;
}
// Given a tree and a path, let's locate a node
function locateNodeFromPath(root, path) {
var current = root;
for(var i = 0, len = path.length; i < len; i++) {
current = current.childNodes[path[i]];
}
return current;
}
function getDoppleganger(rootA, rootB, target) {
return locateNodeFromPath(rootB, getPath(rootA, target));
}
编辑:正如Blue Skies所观察到的那样,childNodes没有.indexOf()。使用Array.prototype.indexOf.call()
进行更新答案 1 :(得分:1)
您可以使用Array.prototype.indexOf.call
(在ES6中标准化)代替Array.from
:
Array.from(travelNode.parentNode.childNodes).indexOf(travelNode);
答案 2 :(得分:1)
这是并行遍历解决方案
function findDomNodeInTree(rootA, rootB, targetNode) {
if (rootA === targetNode){
return rootB;
}
var nodeB = null;
for (let i=0; i<rootA.childNodes.length && nodeB === null; i++){
nodeB = findDomNodeInTree(rootA.childNodes[i], rootB.childNodes[i], targetNode);
}
return nodeB;
}
时间复杂度为O(N),在最坏的情况下,我们需要遍历整个树。
我认为首先找到路径并不比解决方案效率低。在每个级别都有一个indexOf
调用,可能需要遍历该级别上的所有节点以查找索引。
答案 3 :(得分:0)
我将并行遍历两棵树,当我到达treeA中的节点时,返回并行节点。