二叉树遍历 递归/非递归/morris

前序遍历

力扣

递归

class Solution {
public:
    vector<int> ans;
    vector<int> preorderTraversal(TreeNode* root) {
        preorder(root);
        return ans;
    }
    void preorder(TreeNode* root){
        if(root == nullptr) return;
        ans.push_back(root -> val);
        preorder(root -> left);
        preorder(root -> right);
    }
};

非递归

把根节点压入栈,出栈,添加进结果数组中。再把根节点的右指针压入栈,再压入左指针。继续从栈中取出元素,并添加进结果数组中,循环...

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        stack<TreeNode*> s;
        s.push(root);
        while(!s.empty()){
            auto cur = s.top();
            s.pop();
            ans.push_back(cur -> val);
            if(cur -> right) s.push(cur -> right);
            if(cur -> left) s.push(cur -> left);
        }
        return ans;
    }
};

Morris遍历

morris遍历的实现原则

记作当前节点为cur。

  1. 如果cur无左孩子,cur向右移动(cur=cur.right)
  2. 如果cur有左孩子,找到cur左子树上最右的节点,记为mostright
    1. 如果mostright的right指针指向空,让其指向cur,cur向左移动(cur=cur.left)
    2. 如果mostright的right指针指向cur,让其指向空,cur向右移动(cur=cur.right)

实现以上的原则,即实现了morris遍历。

morris遍历的实质

建立一种机制,对于没有左子树的节点只到达一次,对于有左子树的节点会到达两次

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        TreeNode *cur = root, *pre = nullptr;
        while(cur != nullptr){
            pre = cur -> left;
            if(pre){
                while(pre -> right != nullptr && pre -> right != cur)
                    pre = pre -> right;
                if(pre -> right == nullptr){
                    pre -> right = cur;
                    ans.push_back(cur -> val);
                    cur = cur -> left;
                    continue;
                }else{
                    pre -> right = nullptr;
                }
            }else{
                ans.push_back(cur -> val);
            }
            cur = cur -> right;
        }
        return ans;
    }
};

中序遍历

力扣

递归

class Solution {
public:
    vector<int> ans;
    vector<int> inorderTraversal(TreeNode* root) {
        inorder(root);
        return ans;
    }
    void inorder(TreeNode* root){
        if(root == nullptr) return;
        inorder(root -> left);
        ans.push_back(root -> val);
        inorder(root -> right);
    }
};

非递归

初始化一个栈和一个cur节点(指向root),如果栈不为空或者cur不为空就继续循环。如果cur不为空,把cur压入栈,并将cur指向它的左指针,直到为空。如果cur为空,代表已有的左边的节点都遍历过了,那么就把当前节点的值添加进结果数组中,并且让cur指向它的右指针。

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        stack<TreeNode*> s;
        TreeNode* cur = root;
        while(!s.empty() || cur != nullptr){
            if(cur == nullptr){
                cur = s.top();
                s.pop();
                ans.push_back(cur ->val);
                cur = cur -> right;
            }else{
                s.push(cur);
                cur = cur -> left;
            }
        }
        return ans;
    }
};

Morris遍历

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        TreeNode *cur = root, *pre = nullptr;
        while(cur != nullptr){
            pre = cur -> left;
            if(pre){
                while(pre -> right != nullptr && pre -> right != cur)
                    pre = pre -> right;
                if(pre -> right == nullptr){
                    pre -> right = cur;
                    cur = cur -> left;
                    continue;
                }else{
                    pre -> right = nullptr;
                }
            }
            ans.push_back(cur -> val);
            cur = cur -> right;
        }
        return ans;
    }
};

后序遍历

力扣

递归

class Solution {
public:
    vector<int> ans;
    vector<int> postorderTraversal(TreeNode* root) {
        postorder(root);
        return ans;
    }
    void postorder(TreeNode* root){
        if(root == nullptr) return;
        postorder(root -> left);
        postorder(root -> right);
        ans.push_back(root -> val);
    }
};

非递归

把前序遍历倒过来

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        stack<TreeNode*> s;
        s.push(root);
        while(!s.empty()){
            auto cur = s.top();
            s.pop();
            ans.push_back(cur -> val);
            if(cur -> left) s.push(cur -> left);
            if(cur -> right) s.push(cur -> right);
        }
        reverse(ans.begin(), ans.end());
        return ans;
    }
};

初始化栈,root表示当前遍历的节点,prev表示上一次添加进答案的节点,如果栈不为空或root不为空,就继续循环。循环中先找到root的最左节点,寻找的过程中把当前root放入栈中。弹出栈顶元素,保存到root中。如果root的右指针不为空而且root的右指针不是prev,就还需要遍历右节点,把root压入栈,再置root为root的右指针。如果root右指针为空或者右指针已经添加进答案了,就把root添加进答案,修改prev为root,并置root为空。

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        if(root == nullptr) return {};
        vector<int> ans;
        stack<TreeNode*> s;
        TreeNode* prev = nullptr;
        while(!s.empty() || root != nullptr){
            while(root){
                s.push(root);
                root = root -> left;
            }
            root = s.top();
            s.pop();
            if(root -> right != nullptr && root -> right != prev){
                s.push(root);
                root = root -> right;
            }else{
                ans.push_back(root -> val);
                prev = root;
                root = nullptr;
            }
        }
        return ans;
    }
};

Morris遍历 

class Solution {
public:
    vector<int> ans;
    //右孩子指向上一个节点
    TreeNode* ReverseNode(TreeNode* node) {
        TreeNode* pre = nullptr;
        TreeNode* next = nullptr;
        while (node) {
            next = node->right;
            node->right = pre;
            pre = node;
            node = next;
        }
        return pre;
    }

    //逆序打印左孩子的右边界
    void PrintNode(TreeNode* node) {
        TreeNode* tail = ReverseNode(node);
        TreeNode* cur = tail;
        while (cur) {
            ans.push_back(cur -> val);
            cur = cur->right;
        }
        ReverseNode(tail);        //还原
    }

    vector<int> postorderTraversal(TreeNode* root) {
        if (root == nullptr)
            return {};
        TreeNode* cur = root;
        TreeNode* mostRight = nullptr;

        while (cur != nullptr) {
            mostRight = cur->left;
            if (mostRight != nullptr) {
                while (mostRight->right && mostRight->right != cur) {
                    mostRight = mostRight->right;
                }
                if (mostRight->right == nullptr) {  //第一次到达左子树的最右子树
                    mostRight->right = cur;
                    cur = cur->left;
                    continue;
                }
                else {  //第二次到达左子树的最右子树 mostRight->right == cur;
                    mostRight->right = nullptr;
                    //逆序打印左子树的右边界
                    PrintNode(cur->left);
                }
            }
            cur = cur->right;
        }
        PrintNode(root);
        return ans;
    }
};

参考链接:神级遍历——morris - 知乎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值