代码随想录算法训练营第十三天 二叉树的遍历(递归,迭代,层序)
Day13 代码随想录算法训练营第13 天 |二叉树的遍历(递归,迭代,层序)
目录
前言
LeetCode
LeetCode
一、基础
1、二叉树的实现
(1)链式存储
链式存储示意图
(2)数组存储
父节点下标:i
左子节点下标:2i-1
右子节点下标:2i+1
2、二叉树的遍历
遍历本质上是将链表存放的二叉树转换成数组存放的
(1)顺序
前序:中左右
中序:左中右
后续:左右中
前序,中序,后序
(2)深度优先与广度优先
1)深度优先:
先尽可能向下遍历,在遍历过程中将节点放入栈,再按照一定顺序将元素放入数组,顺序包括前序、中序、后序
用一维数组保存结果
2)广度优先:层序遍历
每一层进行遍历,将每一层从左向右先后放进队列,每次取出队首,将队首放入结果内层数组,将队首的左子结点先入队,队首的右子节点后入队。处理完一层以后,内层数组放入结果二维数组。
用二维数组表示结果
二、二叉树的递归遍历
1.前序
class Solution {
public:
void Traversal(TreeNode* p, vector<int>& ans) // ans 是引用
{
if (p == NULL)
return;
ans.push_back(p->val);
Traversal(p->left, ans);
Traversal(p->right, ans);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
Traversal(root, res);
return res;
}
};
2.中序
class Solution {
public:
void Traversal(TreeNode* p, vector<int>& ans) // ans 是引用
{
if (p == NULL)
return;
Traversal(p->left, ans);
ans.push_back(p->val);
Traversal(p->right, ans);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
Traversal(root, res);
return res;
}
};
3.后序
class Solution {
public:
void Traversal(TreeNode* p, vector<int>& ans) // ans 是引用
{
if (p == NULL)
return;
Traversal(p->left, ans);
Traversal(p->right, ans);
ans.push_back(p->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
Traversal(root, res);
return res;
}
};
三、二叉树的迭代遍历
两个操作
处理节点:将节点放入数组(每次将栈顶放入数组)
遍历节点:将节点放入栈
由于栈先入后出,所以先存放到数组的点应该后入栈
1.前序
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
if (root == NULL) return res;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
res.push_back(node->val);
if (node->right) st.push(node->right);
if (node->left) st.push(node->left);
}
return res;
}
2.中序
中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的
94.二叉树的中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if (root != NULL)
st.push(root);
TreeNode* cur = root;
while (!st.empty() || cur != NULL) {
if (cur == root) {
cur = cur->left;
} else if (cur != NULL) {
st.push(cur);
cur = cur->left;
} else {
cur = st.top();
st.pop();
res.push_back(cur->val);
cur = cur->right;
}
}
return res;
}
};
3.后序
前序:中左右
如果把前序中左右子节点入栈先后顺序互换,得到中右左,反转,得到左右中,即后序
LeetCode145.二叉树的后序遍历
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
if (root == NULL) return res;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
res.push_back(node->val);
if (node->left) st.push(node->left);
if (node->right) st.push(node->right);
}
reverse(res.begin(),res.end());
return res;
}
};
四、二叉树的层序遍历
二叉树的层序遍历有十道题,这里选取其中一道
1.题目链接
2.思路
层序遍历属于广度优先搜索
将每一层从左向右先后放进队列,每次取出队首,将队首放入结果内层数组,将队首的左子结点先入队,队首的右子节点后入队。处理完一层以后,内层数组放入结果二维数组
3.题解
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;
vector<vector<int>> ans;
if (root)
q.push(root);
while (!q.empty()) {
vector<int> res;
int n = q.size();
for (int i = 0; i < n; i++) {
TreeNode* p = q.front();
res.push_back(p->val);
q.pop();
if (p->left != NULL)
q.push(p->left);
if (p->right != NULL)
q.push(p->right);
}
ans.push_back(res);
}
return ans;
}
};
总结
二叉树的遍历
遍历本质上是将链表存放的二叉树转换成数组存放的
(1)顺序
前序:中左右
中序:左中右
后续:左右中
(2)深度优先与广度优先
1)深度优先:
先尽可能向下遍历,在遍历过程中将节点放入栈,再按照一定顺序将元素放入数组,顺序包括前序、中序、后序
用一维数组保存结果
2)广度优先:层序遍历
每一层进行遍历,将每一层从左向右先后放进队列,每次取出队首,将队首放入结果内层数组,将队首的左子结点先入队,队首的右子节点后入队。处理完一层以后,内层数组放入结果二维数组。
用二维数组表示结果