leetcode算法总结 —— 二叉树前中后序遍历(迭代和递归两种解法)
Posted Charles Ren
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
};
以上是关于leetcode算法总结 —— 二叉树前中后序遍历(迭代和递归两种解法)的主要内容,如果未能解决你的问题,请参考以下文章