繁体   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