LeetCode 144,94,145 迭代法实现二叉树的先序,中序,后序遍历

Leetcode 先序,中序,后序遍历的题目链接:
144. Binary Tree Preorder Traversal
94. Binary Tree Inorder Traversal
145. Binary Tree Postorder Traversal

warning : 已经熟悉了各种遍历方式的含义以及递归实现的请直接跳到 3

1. 简要介绍一下先序,中序,后序遍历的区别:

例如下面这棵树:

EdmXBn.png
它的遍历结果如下:
先序:8 3 1 6 4 7 10 14 13
中序:1 3 4 6 7 8 10 13 14
后序:1 4 7 6 3 13 14 10 8
     究其根本,按照 xx 序遍历二叉树,xx指定的就是根结点相对于其左右子树(或子节点)的访问次序,例如中序遍历则是先访问左子树,再访问根结点(根节点的访问次序在中间),最后访问右子树。

2. 递归法实现各种遍历

这里用先序举例,递归实现不同遍历方法需要改变的地方就是
cout << root->val << " "这句代码的位置。

void preorder_traversal(TreeNode* root)
{
	if(root == NULL)
		return ;
	cout << root->val << " ";               // 先访问根结点
	preorder_traversal(root->left);         // 再遍历左右子树
	preorder_traversal(root->right);
}
3. 迭代法实现各种遍历
3.1 先序遍历:

   从最简单的开始,先序遍历时先访问根结点,再依次对左右子树进行先序遍历,这里我们需要使用迭代法实现遍历,首先就想到使用栈模拟递归调用过程,每次我们都对以栈顶的节点为根节点的子树进行先序遍历,先序遍历过程就是访问根节点,将右子节点压栈,再将左子节点压栈(注意这里由于栈是先进后出,所以压入顺序和访问顺序相反)。
代码如下:

vector<int> preorderTraversal(TreeNode* root) {
        vector<int> ans;
        if(root == NULL)
            return ans;
        
        stack<TreeNode*> sk;
        sk.push(root);
        
        while(!sk.empty()){
            TreeNode* curr = sk.top();sk.pop();
            ans.push_back(curr->val);
            if(curr->right != NULL)
                sk.push(curr->right);
            if(curr->left != NULL)
                sk.push(curr->left);
            
        }
        return ans;
    }
3.2 后序遍历

   和先序遍历的思想非常类似,仍然是用栈模拟递归。

vector<int> postorderTraversal(TreeNode* root) {
        vector<int> ans;
        stack<int> ans_sk;
        if(root == NULL)
            return ans;
           
        stack<TreeNode*> sk;
        sk.push(root);
        
        while(!sk.empty()){
            TreeNode* node = sk.top();sk.pop();
            ans_sk.push(node->val);
            if(node->left != NULL)
                sk.push(node->left);
            if(node->right != NULL)
                sk.push(node->right);
        }
        while(!ans_sk.empty()){
            ans.push_back(ans_sk.top());
            ans_sk.pop();
        }
        return ans;
    }
3.3 中序遍历

   中序遍历稍微特殊一些,回想一下中序遍历的过程,先遍历左子树,再访问根节点,再遍历右子树,由于对根节点的访问处于中间,不能再像先序和后序那样先访问根节点再将其左右子节点压栈,这里我们采用的解决方法是仍然使用栈模拟这个过程,但是处理方式略有不同,比如我们现在中序遍历一棵树,第一次访问到根节点时我们并不能将它的值直接输出到结果数组中,因为根节点的左子树还没被遍历。我们这里采用的解决方式是,第一次遇到根节点时,记录下根节点的左右子节点,先将右子节点压栈,再将根节点的左右子节点指针置空(这里是想标记下当前这个节点已经被访问过一次),然后将子节点的左子节点压栈,弹栈时如果遇到一个左右子节点都为空的节点,则标志着该节点已经被访问过一次,此时就可以将它的值输出到结果数组中了。
代码如下:

vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ans;
        if(root == NULL)
            return ans;
        
        stack<TreeNode*> sk;
        sk.push(root);
        while(!sk.empty()){
            TreeNode* node = sk.top();sk.pop();
            
            if(node->left == NULL && node->right == NULL)
                ans.push_back(node->val);
            else{
                TreeNode* leftChild = node->left;
                TreeNode* rightChild = node->right;
                node->left = node->right = NULL;
                if(rightChild != NULL)
                    sk.push(rightChild);
                sk.push(node);
                if(leftChild != NULL)
                    sk.push(leftChild);
            }
        } 
        return ans;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值