-1

So I was doing this leetcode question and didn't understand what was happening. It is about preorder traversal through a binary tree.

Problem in question

At first I thought it would be simple enough to implement the traversal code I learned in class.

    vector<int> preorderTraversal(TreeNode* root) {
    vector<int> final;

    if(root == nullptr){
        return final;
    }

    final.push_back(root->val);
    preorderTraversal(root->left);
    preorderTraversal(root->right);

    return final;
}

but then I hit a snag when the code hit a NULL in the left child of the root in one of the test cases.

I scratched my head at what I could do recursively to bypass this problem until I looked at some of the solutions that were posted.

    vector<int>ar1;
void preOrder(TreeNode *root)
{
    if(root==nullptr)
        return;
    ar1.push_back(root->val);
    preOrder(root->left);
    preOrder(root->right);
}
vector<int> preorderTraversal(TreeNode* root) 
{
    preOrder(root);
    return ar1;
}

My question is what makes their traversals using a different method than doing it in the first code snippet?

  • Quick question. What happens to the a `final` returned by the two recursive calls: `preorderTraversal(root->left); preorderTraversal(root->right);` ? – Jerry Coffin Jul 02 '22 at 05:36
  • 1
    vector final; is local variable to the function that is never recaptured by the return, just dropped into the abyss. Where the second solution uses a global varaible to capture it, both are pretty jank, I'd personally pass a reference vector with the TreeNode – Natio2 Jul 02 '22 at 05:54
  • 1
    @Justin just the answer I was looking for, makes sense. As a cs student thanks! – user19464912 Jul 02 '22 at 06:10
  • Happy to help, hopefully the code example is useful. Removing internal state from functions makes them easier to debug, and unit test – Natio2 Jul 02 '22 at 06:15
  • And what snag do you hit with a NULL in the left child of the root? Except for the empty tree every tree has a NULL in the left child at some point and it gets handled just fine. – Goswin von Brederlow Jul 02 '22 at 11:58

1 Answers1

0

Comment with code:

vector final; is local variable to the function that is never recaptured by the return, just dropped into the abyss. Where the second solution uses a global varaible to capture it, both are pretty jank, I'd personally pass a reference vector with the TreeNode

But if you want to do it your way, you'd do something like this (Not using an IDE/compiler, might need some fix-ups)

vector<int> preorderTraversal(TreeNode* root) {
    vector<int> final;

    if(root == nullptr){
        return final;
    }

    final.push_back(root->val);
    auto leftVec = preorderTraversal(root->left);
    if(!leftVec.isEmpty(){
       final.reserve(final.size() + leftVec.size());
       final.insert(std::end(final), std::begin(leftVec ), std::end(leftVec ));
    }

    auto rightVec = preorderTraversal(root->right);
    if(!rightVec.isEmpty(){
       final.reserve(final.size() + rightVec .size());
       final.insert(std::end(final), std::begin(rightVec ), std::end(rightVec ));
    }

    return final;
}

Where the suggested change is this, see how much nicer it is?

Also if you know how many nodes there are on TreeNode you want to reserve the full size before you do any of this if you don't want your code to make a million unnecessary copies.

void preorderTraversal(TreeNode* root, vector<int>& output) {
    if(root == nullptr){
        return;
    }
    
    //Should use emplace back to remove a copy here too
    output.emplace_back(root->val);
    preorderTraversal(root->left, output);
    preorderTraversal(root->right, output);
}
Natio2
  • 235
  • 1
  • 9