前端的數據結構與算法(1)-- dfs

dfs

dfs

前端在開發過程當中接觸到的算法最多的莫過於排序和 dfs(深度優先遍歷) 。 dfs 算法普遍用於圖(樹是圖的一種)的遍歷,如:沒有 querySelectorAll 的時候,根據 classname 或者 tag 查找 element。前端

關於 dfs 算法的遍歷過程,我簡略的畫了一個示例圖:算法

dfs.gif

實例:

最近在實際業務場景中,跟後端約定頁面中全部組件的消息根據頁面上的組件 id 聚合到一個對象中,後端返回的是相似以下的一個樹形數據結構。前端須要把全部的錯誤信息都拿出來,按照頁面上全部組件的順序聚合顯示在一個全局信息面板組件上(至於按照組件順序排序算法本文暫且略過)segmentfault

let tree = {
    'id1': {
        message: 'hello'
    },
    'id2': {
        message: 'world',
        children: {
          'id2-1': {
              message: 'haha',
              children: {
              }
          },
          'id2-2': {
              message: 'heihei'
          }
        }
    }
}

因爲某些大組件多是由多個小組件層層嵌套組合而來,且每一個小組件都有相應的 message 須要展現,因此就選擇了上述的樹形結構來表達組件的信息。這個時候就會有人問,爲何不讓後端把全部 message 都聚合到數組裏面?由於前端不只須要把這些錯誤信息聚合到一塊兒展現,也須要把錯誤定位到具體組件上後端

遞歸版本實現

function dfs(tree = {}, messages = []) {
    let i = 0;
    if(!messages) messages = [];
    if(tree.message) messages.push(tree.message);
    
    const keys = Object.keys(tree.children || {});
    while (i < keys.length) {
        dfs(tree.children[keys[i]], messages);
        i += 1;
    }
    return messages;
}

 tree = {
    message: null,
    children: tree
 };  
 
 dfs(tree);

非遞歸版本實現

function dfs(tree = {}) {
    const array = [tree];
    let messages = [];
    while (array.length) {
      const top = array.pop();
      if (top.message) {
        messages.push(top.message);
      }
      const keys = Object.keys(top.children || {});
      let i = keys.length;
      while (i > 0) {
        i -= 1;
        array.push(top.children[keys[i]]);
      }
    }
    return messages
  }
  
 tree = {
    message: null,
    children: tree
 };  
 
 dfs(tree);

在實際使用中,考慮到數據結構的層數沒那麼多,其實尾遞歸版本和非遞歸版本所消耗的時間在瀏覽器的優化下幾乎可忽略了。數組

相關文章
相關標籤/搜索