算法笔记-二叉树非递归统一遍历法的思考

49 阅读1分钟

代码随想录中给出了二叉树非递归统一遍历方法,原文认为但是统一风格的迭代法并不好理解,而且想在面试直接写出来还有难度的,因此没有给出思路说明。

个人分析

递归时中序遍历二叉树是先遍历左子树到底,然后访问叶子节点,再遍历叶子节点父节点的右子树。 统一遍历,那就是要把访问节点和访问左右子树先后的顺序和递归法保持一致。

trvel(node->left);
node->val;
trvel(node->right);

这里关键节点是:如何判断到了子树底部?

...
while(!st.empty()) {
    TreeNode *node = st.top();
    if (node != nullptr) { // 非标记,继续遍历
        st.pop();
        if (node->right) { st.push(node->right); } // 对应2
        st.push(node); st.push(nullptr); // 对应1, 
        if (node->left) { st.push(node->left);}   // 对应2
    }
    else {     
        st.pop();        // 对应3
        node = st.top(); // 对应3
        result.emplace_back(node->val); // 对应3
        st.pop();
    }
}
...

代码随想录给的代码是这样通过nullptr标记实现的:

  1. 遍历到节点时,一律在节点进栈后加nullptr进栈作为标记,而节点的空子树(nullptr)不进栈;
graph TD; 
    subgraph Stack
        direction LR; 
        A((N1)) --> A1((N2))-->B((leaf))
        end
  1. 当访问到了左右子树均为nullptr的叶子节点时,该叶子节点进栈顶了,在下一轮迭代时会被再次入栈并加nullptr标记;
graph TD; 
    subgraph Stack
        direction LR; 
        A((N1)) --> A1((N2)) --> B((leaf))-->C((nullptr))
        end

3.出现nullptr标记就开始提取节点的元素了

graph TD; 
    subgraph Stack
        direction LR; 
        A((N1)) --> A1((N2))
        end
graph TD; 
    subgraph Stack
        direction LR; 
        A((N1)) --> A1((N2)) --> L1((nullptr))
        end
graph TD; 
    subgraph Stack
        direction LR; 
        A((N1)) --> A1((nullptr))
        end