深度遞歸和廣度遞歸

遞歸react

遞歸算法在平常工做中算是用的比較多的一種,好比DOM樹的遍歷,多層級樹狀結構的生成,遍歷尋找某個樹節點等算法

1 先來看下數據結構數組

var result = {
      id:0,
    name:"張飛",
      item:[
        {id:1,name:"關羽"},
        {id:2,name:"劉備",item:[
          {id:5,name:"荀彧"},
          {id:6,name:"關平"}

        ]},
        {id:3,name:"曹操"},
        {id:4,name:"貂蟬"},
      ]
}

通常狀況下後臺返回相似於如上的嵌套數據結構,或者說只獲得一部分數據,點擊某個子節點,異步加載節點,異步加載以後的數據可能以下:數據結構

var result = {
  id:0,
  name:"張飛",
  item:[
    {id:1,name:"關羽"},
    {id:2,name:"劉備",item:[
      {id:5,name:"荀彧"},
      {id:6,name:"關平"}

    ]},
    //點擊曹操這一項,加載出來劉禪和周倉,點擊周倉,又異步加載項羽和別姬
    {id:3,name:"曹操",item:[
      {id:8,name:"劉禪"},
      {id:9,name:"周倉",item:[
        {id:10,name:"項羽"},
        {id:11,name:"別姬"}
      ]}
    ]},
    {id:4,name:"貂蟬"},
  ]
}

//點擊曹操,返回以下數組
[
  {id:8,name:"劉禪"},
  {id:9,name:"周倉"}
]
//點擊周倉,返回以下數組
[
  {id:8,name:"項羽"},
  {id:9,name:"別姬"}
]

2 如何實現項目中的需求異步

以目前我作的一個react項目爲例:需求是函數

  • 將相似於這樣的數據以樹狀結構展現出來
  • 異步加載子節點的數據,有多是加載子節點,有多是加載同級節點
  • 因此就須要定位到每次點擊的節點的位置,而後根據其餘屬性判斷如何添加節點
  • 關鍵就是如何經過遞歸找到對應id的節點位置

個人實現思路就是維持一個state狀態對象,每次異步請求回來的數據,根據返回的id來判斷點擊的位置(數據中全部節點id惟一),進而將數據添加到state中對應的id位置中優化

3 代碼實現遞歸code

  • 深度優先
var item = [result]
//設置一個全局的value,存放找到對應item的時候的引用地址
var value = null ;
//函數要有返回值,不然默認返回undefiend
function getName(item,id){
  if(!item) return null ;
  for (var i = 0 ;i<item.length;i++){
    if(item[i].id == id) {
      value = item[i]
      break ;
    };
    if(item[i].item){
      getName(item[i].item,id)
    };
  }
  return value ;
}
//能夠試着改變id看下效果,最好打下斷點 ,能夠更加深入的瞭解下程序運行的過程
var foundName = getName(item,7);
console.log('foundName',foundName)

若是想要更加的通用一些,能夠稍加優化一下對象

var item = [result]
function getName(item,id){
  let value = null ;
  let ret = recurision(item,id);
  return ret ;
  function recurision(item,id){
    if(!item) return null ;
    for (var i = 0 ;i<item.length;i++){
      console.log(item[i].id);//記錄遞歸的執行軌跡
      if(item[i].id == id) {
        value = item[i]
        break ;
      };
      if(item[i].item){
        recurision(item[i].item,id)
      };
    }
    return value;
  }
}

var foundName = getName(item,9);
console.log('foundName',foundName)

以上代碼實現遞歸的核心思路是依靠聲明一個外部的變量,遞歸函數內部進行查找,若是找到對應的item,則將此item賦值給value,遞歸函數返回改value值;遞歸

總感受代碼還不夠簡潔,你們有好的思路歡迎隨時交流。

上面這種方法,傳入的item是數組,當時考慮的是傳入數組可能會方便一些;

下面這種方法傳入的rootItem是對象,感受下面這種方法會比較好一些;

這二者採起的遞歸方式都是深度優先的搜索方式,經過咱們記錄遞歸的執行軌跡能夠看出來;

====2017/9/20更新,地鐵上看了一些文章;優化一下代碼;

function transerDF(rootItem,id){
  var value = null ;
  (function recurse(currentItem){
    if(currentItem == null) return null ;
    console.log(currentItem.id);//記錄遞歸的執行軌跡
    if(currentItem.item){
      for(var i = 0 ; i < currentItem.item.length ; i++){
        recurse(currentItem.item[i])
      }
    }
    if(currentItem.id == id){
      value = currentItem;
    }
  })(rootItem)
  return value ;
}
var ret = transerDF(result,1);
console.log(ret);
  • 廣度優先
function transerBF(rootItem,id){
  var value ;
  var queue = [];//用數組模擬隊列
  queue.push(rootItem);//放入隊列末尾
  var currentItem = queue.shift();//取出隊列中的首位
  while(currentItem){
    console.log(currentItem.id);//記錄遞歸軌跡
    if(currentItem.item){
      for(var i=0;i<currentItem.item.length;i++){
        queue.push(currentItem.item[i]);
      }
    }
    if(currentItem.id == id ){
      value = currentItem;
    }
    currentItem = queue.shift();
  }
  return value;
}
var ret = transerBF(result,11);
console.log(ret);

以上分析經過記錄遞歸軌跡,咱們能夠很清晰的看到遞歸執行的順序以及深度遞歸和廣度遞歸不一樣的實現思想;

jimwmg@foxmail.com

相關文章
相關標籤/搜索