簡體   English   中英

Javascript-ONLY DOM Tree Traversal - DFS和BFS?

[英]Javascript-ONLY DOM Tree Traversal - DFS and BFS?

任何人都可以提供代碼,偽代碼,甚至提供在純JavaScript(無JQuery或任何幫助庫)中實現DFS和BFS的良好鏈接? 我一直試圖理解如何實現任一遍歷,但我似乎無法真正區分BFS和DFS實現的區別。

如果我們想要一個具體問題作為一個例子:我想在給定節點遍歷DOM,並獲取所有類名。

(我能想到遍歷的唯一方法是遍歷每個父節點,從該節點得到我需要的東西,在這個例子中是類名,然后看看他們是否有孩子,為每個孩子遞歸。我相信這是DFS ?同樣,我很難理解DOM遍歷實現中的差異!)

最后,對不起,如果這是重復。 我到處尋找好的,明確的例子,但沒有找到任何好的答案! 如果那里有一個很好的答案,請告訴我:)

我們使用以下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 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);

此代碼將一直存在,直到堆棧中有任何節點。 在每一步中,我們得到堆棧中的頂級節點,如果它不是null,並且如果我們之前沒有訪問它,那么我們訪問它並將其所有子節點添加到堆棧中。

隊列通常用於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);

此代碼將一直存在,直到隊列中有任何節點。 在每個步驟中,我們得到隊列中的第一個節點,如果它不是null,並且如果我們之前沒有訪問它,那么我們訪問它並將其所有子節點添加到隊列中。

請注意,兩種算法的主要區別在於我們使用的數據類型。

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);

這循環遍歷元素,將他們的孩子推到堆棧上,然后再次啟動它們。 正如你所看到的,這會消耗更多的空間(孩子的陣列),這不是最好的......

對於DFS,您可以使用TreeWalkerNodeIterator API並使用NodeFilter.SHOW_ELEMENT過濾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM