leetcode算法总结 —— 二叉树前、中、后序遍历(迭代和递归两种解法)

前中后序遍历递归

时间和空间复杂度都是O(n)

空间复杂度取决于递归的栈深度(树的高度),而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。

1. 递归

class Solution {
    public:
	vector<int> preorderTraversal(TreeNode *root)
	{
		vector<int> res;
		dfs(root, res);
		return res;
	}
	//传引用相当于传一个全局变量
	void dfs(TreeNode *root, vector<int> &res)
	{
		if (root == nullptr)
			return;
		//前序遍历
		res.push_back(root->val);
		dfs(root->left, res);
		//中序遍历
		//res.push_back(root->val);
		dfs(root->right, res);
		//后序遍历
		//res.push_back(root->val);
	}
};

2. 迭代,易理解解法

时间复杂度为O(n)。因为每个节点只遍历一次。
空间复杂度最大O(n)。只有当二叉树成为一条链的时候,栈需要存储所有节点,不然栈只需要存储一部分。

前序

   vector<int> preorderTraversal(TreeNode* root) {
       stack<TreeNode*> st;
       vector<int> vRes;
       if (root == NULL) return vRes;
       st.push(root);
       while (!st.empty()) {
		//取栈顶元素,也就是中值
           TreeNode* node = st.top();                     
           st.pop();
           vRes.push_back(node->val);
		//如果非空,则右子节点入栈,因为是中左右的顺序,所以右先入,然后左入
           if (node->right) st.push(node->right);          
           if (node->left) st.push(node->left); 
		//下次先拿左子节点,然后再判断           
       }
       return vRes;
   }

中序遍历

    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> vRes;
        stack<TreeNode*> st;
        //栈中有元素或者当前节点不为空时进行循环
        //这是模拟递归的调用
        while(st.size() > 0 || root != nullptr) {
            //如果当前节点不为空,则入栈并不断往左子树方向走
            if(root != nullptr) {
                st.push(root);
                root = root->left;  
            }
            //如果当前节点为空,说明走到头了
            //从栈顶取元素,此时节点为中,并保存
            //然后转向右边节点,也就是左中右的顺序,继续上面整个过程
            else {
                TreeNode *tmp = st.top();
                st.pop();
                vRes.push_back(tmp->val);
                root = tmp->right;
            }
        }
        return vRes;
    }

后序遍历

 vector<int> postorderTraversal(TreeNode *root)
    {
        vector<int> v;
        if (root == nullptr)
            return v;
        stack<TreeNode *> s;
        s.push(root);

        while (!s.empty())
        {
            TreeNode *tempNode = s.top();
            s.pop();
            //先访问的是根节点
            v.push_back(tempNode->val);

            // 根右左,正好是后续遍历的倒序
            if (tempNode->left != nullptr)
            {
                s.push(tempNode->left);
            }
            if (tempNode->right != nullptr)
            {
                s.push(tempNode->right);
            }
        }
        //时间复杂度O(n)
        reverse(v.begin(), v.end()); //最后反向一下
        return v;
    }

3. 迭代统一解法

模板

//模拟递归操作
//模板是根,左,右的顺序
while (root != nullptr || !stk.empty()) {
	//如果当前节点非空,一直遍历到最左子树
	while (root != nullptr) {
		//根
		stk.push(root);
		//左
		root = root->left;
	}
	//如果root为空也就是左为空,则取出栈顶节点,也就是中
	root = stk.top();
	stk.pop();

	//做判断或者操作
	
	//移动到中的右子节点
	root = root->right;
}

前序遍历

时间复杂度为O(n)。因为每个节点只遍历一次。
空间复杂度最大O(n)。只有当二叉树成为一条链的时候,栈需要存储所有节点,不然栈只需要存储一部分。

class Solution {
    public:
	vector<int> preorderTraversal(TreeNode *root)
	{
		vector<int> res;
		stack<TreeNode *> stk;
		while (root != nullptr || !stk.empty()) {
			//一直遍历到最左子树
			//因为是前序遍历,根左右的顺序,所以向左走的时候保存
			while (root != nullptr) {
				res.push_back(root->val);
				stk.push(root);
				root = root->left;
			}
			//这时左子树都入栈了
			//如果最左为空,则取中
			//取出栈顶节点
			root = stk.top();
			stk.pop();
			//因为中已经保存了,根左右的顺序,移动到右子节点
			//最左节点移动到右子树
			root = root->right;
		}
		return res;
	}
};

中序遍历

class Solution {
    public:
	//中序遍历:左中右的顺序
	vector<int> inorderTraversal(TreeNode *root)
	{
		vector<int> res;
		stack<TreeNode *> stk;
		while (root != nullptr || !stk.empty()) {
			//一直遍历到最左子树
			//因为是中序遍历,左根右的顺序,先不保存
			while (root != nullptr) {
				stk.push(root);
				root = root->left;
			}
			//这时左子树都入栈了
			//如果最左为空,则取中
			//取出栈顶节点
			root = stk.top();
			stk.pop();

			//保存
			res.push_back(root->val);
			//移动到中的右子节点
			root = root->right;
		}
		return res;
	}
};

后序遍历

class Solution {
    public:
	vector<int> postorderTraversal(TreeNode *root)
	{
		vector<int> res;
		stack<TreeNode *> stk;

		TreeNode *prev = nullptr;
		while (root != nullptr || !stk.empty()) {
			//一直遍历到最左子树
			//因为是中序遍历,左右根的顺序,先不保存
			while (root != nullptr) {
				stk.push(root);
				root = root->left;
			}
			//这时左子树都入栈了
			//如果最左为空,则取中
			//取出栈顶节点
			root = stk.top();
			stk.pop();
			//如果右子树为空或者访问过
			//则保存当前节点
			//保存当前节点的前一个节点
			if (root->right == nullptr || root->right == prev) {
				res.push_back(root->val);
				prev = root;
				root = nullptr;
			} else {
				//如果不为空并且没访问过,则入栈,并进入到右子树
				stk.push(root);
				root = root->right;
			}
		}
		return res;
	}
};

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>