簡體   English   中英

尾遞歸二叉樹搜索 Function JS

[英]Tail Recursive Binary Tree Search Function JS

我正在嘗試編寫一個尾遞歸 function contains(tree,element) 如果該元素存在於二叉樹中則返回 true,否則返回 false。

我寫了遞歸 function,問題是我不知道如何讓它尾遞歸

let leaf = { val: 6 }
let tree = {
  val: 10,
  sx: {
    val: 5,
    sx: {
      val: 13
    },
    dx: leaf
  },
  dx: {
    val: 32,
    sx: null,
    dx: null
  }
}

function contains(t,x) {

  if(t.val == x)
    return 1;

  let res = 0 ;
  if(t.sx)
    res += contains(t.sx,x)
  if(t.dx)
    res += contains(t.dx,x)

  return Boolean(res)
}

console.log(contains(tree,6))

我認為這不可能使完全尾遞歸,因為遞歸調用的次數可能是 1 或 2(或 0)- 在 2 的情況下,您不能無條件返回 function 的最終計算,因為您不知道特定的遞歸調用是否是 function 的最終計算。

也就是說,您可以改進您的代碼。 如果val匹配,則返回true ,而不是添加到res變量,如果它們為真,則立即返回第一個遞歸調用。 第二次調用可以進行尾遞歸,因為在那個時候,沒有什么可以檢查分支了。

 let leaf = { val: 6 } let tree = { val: 10, sx: { val: 5, sx: { val: 13 }, dx: leaf }, dx: { val: 32, sx: null, dx: null } } function contains(t, x) { if (t.val == x) { return true; } // Recursive, but not tail recursive: if (t.sx && contains(t.sx, x)) { return true; } // Tail recursive: return.t?dx: false. contains(t,dx; x). } console,log(contains(tree, 6))

對於那些感興趣的人,我留下二叉搜索樹的尾遞歸版本

let leaf = { val: 7}
let tree = {
  val: 10,
  sx: {
    val: 5,
    sx: {
      val: 4
    },
    dx: leaf
  },
  dx: {
    val: 32,
    sx: null,
    dx: null
  }
}

function _contains(t,x) {
  
  if(t.val == x)
    return 1;
  

  if(x < t.val && t.sx)
    return _contains(t.sx,x)
  else if(t.dx)
    return _contains(t.dx,x)    
}
function contains(t,x){
  
  return Boolean(_contains(t,x));
}

雖然這里的討論已經提出了二叉搜索樹的尾遞歸解決方案,但似乎可以為任意二叉樹(或者實際上是任何樹)做一個尾遞歸版本。技巧是我們的核心 function 將在一節點上運行,而不是在單個節點上運行。

在這里,我們對樹進行廣度優先遍歷,在找到值或用完節點時停止。 我們的遞歸調用在輸入數組的尾部加上節點的左右子節點上運行。 (不存在或null個節點將被忽略。)

公共 function 只是將輸入樹包裝在一個數組中,並將其傳遞給我們的主 function。

 const _contains = ([t, ...ts], x) => t == undefined? false: t.val == x? true: _contains (ts.concat (t.sx || []).concat (t.dx || []), x) const contains = (t, x) => _contains ([t], x) let tree = {val: 10, sx: {val: 5, sx: {val: 13}, dx: {val: 6}}, dx: {val: 32, sx: null, dx: null}}; [10, 12, 13, 32, 42].forEach (x => console.log (`${x} --> ${contains (tree, x)}`))

根據一般原則,我不願意這樣做,但是如果我們將孩子推到數組上並在索引上重復出現,這肯定會變得更加有效,就像這樣:

const push = (x) => (xs) => 
  x ? ((xs .push (x)), xs) : xs

const _contains = (ts, i, x) =>
  i >= ts .length
    ? false
  : ts [i] .val == x
    ? true
  : _contains (push (ts [i] .dx) (push (ts [i] .sx) (ts)), i + 1, x)

const contains = (t, x) =>
  _contains ([t], 0, x)

但要點很簡單,通過使用節點數組,我們可以為似乎永遠不會出現的 TCO 做好准備,除非您是Safari用戶。

暫無
暫無

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

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