一、层序遍历
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/
解题方法:
- 借助一个队列,先把根节点入队,每次从队列中取数据入数组,然后判断左右是否为空不为空则入队
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root)
{
vector<vector<int>> res;
if(root == nullptr)
return res;
queue<TreeNode*> que_;
que_.push(root);
while(!que_.empty())
{
size_t LevelSize = que_.size();
TreeNode* node = nullptr;
vector<int> tmp;
for(size_t i = 0; i < LevelSize; i++)
{
node = que_.front();
que_.pop();
tmp.push_back(node->val);
if(node->left)
que_.push(node->left);
if(node->right)
que_.push(node->right);
}
res.push_back(tmp);
}
return res;
}
};
二、前序遍历
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
解题方法:
- 递归:每次递归前先插入当前节点,然后遍历左树和右树
class Solution {
public:
vector<int> res;
void VLR(TreeNode* root)
{
if(root == nullptr)
return;
res.push_back(root->val);
VLR(root->left);
VLR(root->right);
}
vector<int> preorderTraversal(TreeNode* root)
{
VLR(root);
return res;
}
};
- 非递归:借助一个栈结构,先插入根节点,只要栈不空,就一直出栈并插入数组。根据栈的先进后出性质,要先插入右树,再插入左树
class Solution
{
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> res;
if(root == nullptr)
return res;
stack<TreeNode*> stc;
stc.push(root);
TreeNode* node = nullptr;
while(!stc.empty())
{
node = stc.top();
stc.pop();
res.push_back(node->val);
if(node->right)
stc.push(node->right);
if(node->left)
stc.push(node->left);
}
return res;
}
};
三、中序遍历
递归思路:
- 先遍历左树,在遍历完左树后,回溯的时候再进行插入数据
class Solution {
public:
vector<int> res;
void LVR(TreeNode* root)
{
if (root == nullptr)
return;
LVR(root->left);
res.push_back(root->val);
LVR(root->right);
}
vector<int> inorderTraversal(TreeNode* root)
{
LVR(root);
return res;
}
};
非递归思路:
- 模拟递归,先循环遍历左树,将路径上的每个节点入栈
- 若已经遍历到空节点,则退出循环,取栈顶元素,并将栈顶元素插入数组
- 让节点指向右树:
若右树不空,则会进入下一个遍历入栈循环
若右树为空,则取栈顶的下一个元素 - 直到栈为空,或者root节点为空,则停止循环
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root)
{
if (root == nullptr)
return vector<int>();
stack<TreeNode*> stc;
vector<int> ans;
while (root != nullptr || !stc.empty())
{
while (root != nullptr)
{
stc.push(root);
root = root->left;
}
root = stc.top();
stc.pop();
ans.push_back(root->val);
root = root->right; // 若root的右树存在,
}
return ans;
}
};
值得注意的是: 循环结束条件 !stc.empty() || cur != nullptr
,在访问完左支之后可能 cur 不空,意味着右支还没访问到。
四、后序遍历
递归思路:
- 先递归访问左支和右支,在遍历完成左右树后,回溯的时候插入根节点
class Solution {
public:
vector<int> res;
void LRV(TreeNode* root)
{
if(root == nullptr)
return;
LRV(root->left);
LRV(root->right);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root)
{
LRV(root);
return res;
}
};
非递归思路:
- 模拟递归,先遍历左树,将路径上的所有节点入栈
- 若已经遍历到空节点,则
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root)
{
if (root == nullptr)
return vector<int>();
stack<TreeNode*> stc;
vector<int> ans;
TreeNode* prev = nullptr;
while (root != nullptr || !stc.empty())
{
while (root != nullptr)
{
stc.push(root);
root = root->left;
}
TreeNode* cur = stc.top();
if (cur->right == nullptr || cur->right == prev)
{
stc.pop();
ans.push_back(cur->val);
prev = cur;
}
else
root = cur->right;
}
return ans;
}
};
值得注意的: 每次执行完左支后都要判断右支是否为空,或者右支是否已经被访问过。每次执行完删除操作之后,都应该让前驱节点 pre 指向 cur 节点。