目录
树的遍历总结
遍历方式概述
二叉树的遍历分为以下三种:
- 先序遍历:遍历顺序规则为 先遍历根节点,再遍历左子树,最后遍历右子树(根-左-右)
- 中序遍历:遍历顺序规则为 先遍历左子树,再遍历根节点,最后遍历右子树(左-根-右)
- 后序遍历:遍历顺序规则为 先遍历左子树,再遍历右子树,最后遍历根节点(左-右-根)
1. 先序遍历
- 先序遍历:遍历顺序规则为 先遍历根节点,再遍历左子树,最后遍历右子树(根-左-右)
1.1 前序遍历递归写法
Leetcode 144. 二叉树的前序遍历 递归写法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root, vector<int> &res){
// 如果根节点 为空,直接返回
if(root == NULL) return ;
// 根节点不为空,加入到遍历的数组中
res.push_back(root->val);
// 添加完根节点之后,遍历左节点
dfs(root->left, res);
// 添加完左节点之后,遍历右节点
dfs(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if(root == NULL) return res;
dfs(root, res);
return res;
}
};
执行结果
(./images/144%20result_preorderTraversal.png)]
1.2 前序遍历迭代写法1
Leetcode 144. 二叉树的前序遍历 迭代写法 1
关键代码
while(!st.empty()){
// 使用stack 存储右左节点 和遍历的左右顺序相反,先进后出
TreeNode *temp = st.top();
st.pop();
if(!temp) continue;
res.push_back(temp->val);
// 先后将 右左节点压入栈中
if(temp->right) st.push(temp->right);
if(temp->left) st.push(temp->left);
}
源代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
// 前序遍历 根左右
vector<int> res;
if(root == NULL) return res;
stack<TreeNode*> st;
st.push(root);
while(!st.empty()){
TreeNode *temp = st.top();
st.pop();
if(!temp) continue;
res.push_back(temp->val);
if(temp->right) st.push(temp->right);
if(temp->left) st.push(temp->left);
}
return res;
}
};
执行结果
1.3 前序遍历迭代写法2
Leetcode 144. 二叉树的前序遍历 迭代写法 2
关键代码
while(cur || !st.empty()){
while(cur){
st.push(cur);
res.push_back(cur->val);
cur=cur->left;
}
cur = st.top();
st.pop();
cur = cur->right;
}
return res;
源代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root, vector<int> &res){
// 如果根节点 为空,直接返回
if(root == NULL) return ;
// 根节点不为空,加入到遍历的数组中
res.push_back(root->val);
// 添加完根节点之后,遍历左节点
dfs(root->left, res);
// 添加完左节点之后,遍历右节点
dfs(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
// 前序遍历 根左右
vector<int> res;
if(root == NULL) return res;
stack<TreeNode*> st;
TreeNode *cur= root;
while(cur || !st.empty()){
while(cur){
st.push(cur);
res.push_back(cur->val);
cur=cur->left;
}
cur = st.top();
st.pop();
cur = cur->right;
}
return res;
}
};
执行结果
2. 中序遍历
- 中序遍历:遍历顺序规则为 先遍历左子树,再遍历根节点,最后遍历右子树(左-根-右)
2.1 中序遍历递归写法
LeetCode 94. 二叉树的中序遍历 递归写法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root, vector<int> &res){
// 如果根节点 为空,直接返回
if(root == NULL){
return ;
}
// 一直遍历 左节点 直到左节点为空,将根节点压入数组, 然后遍历右节点
dfs(root->left, res);
res.push_back(root->val);
dfs(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if(root == NULL) return res;
dfs(root, res);
return res;
}
};
执行结果
2.2 中序遍历迭代写法
LeetCode 94. 二叉树的中序遍历 迭代写法
关键代码
while(cur || !st.empty()){ //
while(cur){ // 将根节点和所有左子树节点入栈
st.push(cur);
cur=cur->left;
}
cur = st.top(); //
st.pop();
res.push_back(cur->val);
cur = cur->right;
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
// 中序遍历的顺序是 左中右 先进后出 使用栈来实现
vector<int> res;
if(root == NULL) return res;
TreeNode *cur = root;
stack<TreeNode*> st;
while(cur || !st.empty()){ //
while(cur){ // 将根节点和所有左子树节点入栈
st.push(cur);
cur=cur->left;
}
cur = st.top();
st.pop();
res.push_back(cur->val);
cur = cur->right;
}
return res;
}
};
执行结果
3. 后序遍历
- 后序遍历:遍历顺序规则为 先遍历左子树,再遍历右子树,最后遍历根节点(左-右-根)
3.1 后序遍历递归写法
LeetCode 145. 二叉树的后序遍历 递归写法
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root, vector<int> &res){
if(root == NULL) return ;
dfs(root->left, res);
dfs(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
dfs(root, res);
return res;
}
};
执行结果
3.2 后序遍历迭代写法
LeetCode 145. 二叉树的后序遍历 迭代写法
后续遍历的迭代代码是最难的一个。二叉树的后续遍历时最难的一种遍历方式,因为无法判定是否遍历过右子树,所以无法判断是否访问当前节点(只有访问过右子树后才能访问父节点)。
-
问题:如何确定当前状态是访问了左子树后过来,还是访问了右子树后来的?
-
如果是访问左子树后过来,那么要访问右子树,如果是访问右子树后过来,那么访问当前节点
-
我们可以根据这一特性来分辨:
如果是访问的右子树过来,那么上次访问结果是当前的右子树,通过记录上个访问的节点,即可解决该问题。
关键代码
while(cur || !st.empty()){
while(cur){
st.push(cur);
cur= cur->left;
}
cur = st.top(); // get the top element of stack
st.pop();
if((cur->right == NULL)|| (cur->right == pre_visit)){
pre_visit = cur; // 记录 上一个访问的节点是哪一个
res.push_back(cur->val);
cur = NULL; // 下一步就是弹栈
}
else{
st.push(cur);
cur = cur->right;
}
}
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void dfs(TreeNode* root, vector<int> &res){
if(root == NULL) return ;
dfs(root->left, res);
dfs(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(!root) return res;
stack<TreeNode*> st;
TreeNode *cur = root;
TreeNode * pre_visit;
while(cur || !st.empty()){
while(cur){
st.push(cur);
cur= cur->left;
}
cur = st.top(); // get the top element of stack
st.pop();
if((cur->right == NULL)|| (cur->right == pre_visit)){
pre_visit = cur; // 记录 上一个访问的节点是哪一个
res.push_back(cur->val);
cur = NULL; // 下一步就是弹栈
}
else{
st.push(cur);
cur = cur->right;
}
}
return res;
}
};