三题都是二叉树遍历,只不过是遍历序的问题。
三题都可以共用一个算法,取决于什么时候插入值。其中,【后序遍历】(左->右->根)可以通过【魔改的前序遍历】(根->右->左)的结果反转得到。
迭代解决二叉树遍历,主要在于我要知道什么时候某棵子树遍历完了。
例如,对于栈算法,我可以一直对左节点压栈。当节点被弹出,说明其左子树已经被访问完毕,于是访问其右子树。
Morris 算法的思想是这样的:找到一个机制,让我们能知道左子树遍历完了。
这个机制就是在【左子树的最右节点】插入一个右指针,使其指向根节点。
这样的话,当最右节点试图访问它的右节点,就会回到根部。
这时候,根部节点再次去尝试找【左子树的最右节点】,就会找到他自己。
这时候他就知道左子树已经遍历完成,只需要把这个最右节点的连接切断就可以了。
算法见下。后序遍历就在前序遍历的基础上,修改对应左右边即可。
class Solution { public: vector<int> TraverseTemplate(TreeNode* root) { vector<int> ans; while(root != nullptr){ if(root->left != nullptr){ TreeNode* pred = root->left; while(pred->right != nullptr && pred->right != root) pred = pred->right; if(pred->right == nullptr){ // 对于前序,在这里插入 // ans.emplace_back(root->val); pred->right = root; root = root->left; } else{ // == root, visit back! // 对于中序,在这里插入 // ans.emplace_back(root->val); pred->right = nullptr; root = root->right; } } else{ ans.emplace_back(root->val); root = root->right; } } return ans; } };
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
while(root != nullptr){
if(root->left != nullptr){
TreeNode* pred = root->left;
while(pred->right != nullptr && pred->right != root) pred = pred->right;
if(pred->right == nullptr){
pred->right = root;
root = root->left;
}
else{ // == root, visit back!
ans.emplace_back(root->val);
pred->right = nullptr;
root = root->right;
}
}
else{
ans.emplace_back(root->val);
root = root->right;
}
}
return ans;
}
};