-1

I want to optimize this dfs with tail recursion,but i don't konw how to realize it, could any help me?

My first solution is the following code, i want modify it with tail recursion to get test case with 21

const tree = {
  val: 1,
  children: [
    { val: 2, children: [] },
    {
      val: 3,
      children: [
        { val: 4, children: [] },
        { val: 5, children: [] },
      ],
    },
    { val: 6, children: [] },
  ],
};


function dfs(root) {
  if (root.children && root.children.length > 0) {
    let tmp = 0;
    for (let i = 0; i < root.children.length; i++) {
      tmp += dfs(root.children[i]);
    }
    return (tmp += root.val);
  } else {
    return root.val;
  }
}

let ret = 0;
console.log("ret: ", dfs(tree));//get 21 this case

1
  • 2
    Most JavaScript engines don’t have tail call elimination, so note that this won’t be an optimization. Also, DFS isn’t really suited to tail calls – you may as well just use an array as a stack with a loop if that’s what you were going to do with tail recursion. Commented Jan 14, 2024 at 7:39

3 Answers 3

1

Most JavaScript engines do not currently implement tail call optimisation, but if you really want a tail call, and it must be depth-first order, then you will need to mimic the iterative algorithm, and pass a stack reference to the tail call.

Here is a recursive function with a tail call that performs a pre-order traversal. It uses the stack to keep track of the current indices in each of the unfinished children arrays.

const preorder = ({val, children}, stack=[], sum=0) => {
    let i = 0;
    if (!children?.length) {
        if (!stack.length) return sum + val; // Last value in preorder sequence
        [children, i] = stack.splice(-2); // Get next sibling: children[i]
    }
    if (i + 1 < children?.length) stack.push(children, i + 1);
    return preorder(children[i], stack, sum + val);
}


// Example tree
const tree = {val: 1,children: [{ val: 2, children: [] },{val: 3,children: [{ val: 4, children: [] },{ val: 5, children: [] },],},{ val: 6, children: [] },],};
console.log(preorder(tree));

Sign up to request clarification or add additional context in comments.

Comments

-1

DFS doesn't play nicely with tail recursion. You can hack around that, for example, by passing an explicit list of "nodes-to-visit", as in

function sum(todo, total=0) {
    if (todo.length === 0)
        return total

    let [node, ...rest] = todo
    return sum([...rest, ...node.children], total + node.val)
}

//

const tree = {
    val: 1,
    children: [
        { val: 2, children: [] },
        {
            val: 3,
            children: [
                { val: 4, children: [] },
                { val: 5, children: [] },
            ],
        },
        { val: 6, children: [] },
    ],
};



let ret = 0;
console.log("ret: ", sum([tree])); //get 21 this case

...but that hardly counts as an "optimization".

1 Comment

This is quite memory intensive, each newly created array passed as argument being referenced from the call stack until the end. Recreating arrays at every call costs time too.
-1

You can use reduce method and arrow function to optimize.


function dfs(root) {
   return root.val + root.children.reduce((sum, child) => sum + dfs(child), 0);
}

1 Comment

Definitely cleaner, but not a tail call (or really an optimization).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.