Javascript-ONLY DOM Tree Traversal - DFS和BFS?

时间:2016-09-15 05:45:24

标签: javascript dom traversal depth-first-search breadth-first-search

任何人都可以提供代码,伪代码,甚至提供在纯JavaScript(无JQuery或任何帮助库)中实现DFS和BFS的良好链接吗?我一直试图了解如何实现任何遍历,但我似乎无法真正区分BFS和DFS实现的差异。

如果我们想要一个具体问题作为例子:我想在给定节点遍历DOM,并获取所有类名。

(我认为遍历的唯一方法是遍历每个父节点,从该节点得到我需要的东西,在这个例子中是类名,然后看看他们是否有孩子,为每个孩子递归。我相信这是DFS?再次,我很难理解DOM遍历实现的差异!)

最后,抱歉,如果这是重复。我到处寻找好的,明确的例子,但没有找到任何好的答案!如果那里已经有了一个很好的答案,请告诉我:)

3 个答案:

答案 0 :(得分:10)

让我们使用以下HTML代码作为示例:

<div class="a">
    <div class="aa">
        <span class="aaa">
        </span>
        <span class="aab">
        </span>
    </div>
    <div class="ab">
        <span class="aba">
        </span>
        <span class="abb">
        </span>
    </div>
</div>

DFS将始终首先进入下一级节点,并且只有当没有更多未遍历的子节点时才会进入当前级别的下一个节点。

DFS将按以下顺序遍历示例的节点:

a, aa, aaa, aab, ab, aba, abb

BFS将始终首先遍历当前级别中的所有节点,然后才会进入下一级节点。

BFS将按以下顺序遍历示例的节点:

a, aa, ab, aaa, aab, aba, abb

没有明确的答案,你应该使用其中一个。通常取决于您的需求。

实施细节:

对于DFS人来说,经常使用stack

伪代码:

stack my_stack;
list visited_nodes;
my_stack.push(starting_node);

while my_stack.length > 0
   current_node = my_stack.pop();

   if current_node == null
       continue;
   if current_node in visited_nodes
      continue;
   visited_nodes.add(current_node);

   // visit node, get the class or whatever you need

   foreach child in current_node.children
      my_stack.push(child);

此代码将一直存在,直到堆栈中有任何节点。在每个步骤中,我们得到堆栈中的顶级节点,如果它不是空的,并且如果我们之前没有访问它,那么我们访问它并将其所有子节点添加到堆栈中。

Queue通常用于BFS。

伪代码:

queue my_queue;
list visited_nodes;
my_queue.enqueue(starting_node);

while my_queue.length > 0
   current_node = my_queue.dequeue();

   if current_node == null
       continue;
   if current_node in visited_nodes
      continue;
   visited_nodes.add(current_node);

   // visit node, get the class or whatever you need

   foreach child in current_node.children
      my_queue.enqueue(child);

此代码将一直存在,直到队列中有任何节点。在每个步骤中,我们得到队列中的第一个节点,如果它不是空的,并且如果我们之前没有访问它,那么我们访问它并将其所有子节点添加到队列中。

请注意,两种算法的主要区别在于我们使用的数据类型。

答案 1 :(得分:4)

DFS:

function m(elem) {
    elem.childNodes.forEach(function(a) {
        m(a);
    });
    //do sth with elem
}
m(document.body);

这会循环遍历所有元素,并且每个元素都会循环播放每个子元素等等。

BFS:

var childs = [];

function m(elem) {
    elem.childNodes.forEach(function(a) {
        childs.push(a);
    });
    b = childs;
    childs = [];
    b.forEach(function(a) {
        m(a);
    });
}
m(document.body);

这循环通过元素,将他们的孩子推到堆栈上,然后再次启动它们。正如你所看到的,这会消耗更多空间(childs数组),这不是最好的......

答案 2 :(得分:4)

对于DFS,您可以使用TreeWalkerNodeIterator API并使用NodeFilter.SHOW_ELEMENT进行过滤。