文章目录
节点定义
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) {}
};
一、深度优先遍历
leetcode题目:
144.二叉树的前序遍历
094.二叉树的中序遍历
145.二叉树的后序遍历
1.1 递归法
1.1.1 前序遍历
void traversal(TreeNode* curr, vector<int> &vec) {
if(curr == nullptr) return; //递归终止条件
vec.push_back(curr -> val); //中,处理节点
traversal(curr -> left, vec); //左
traversal(curr -> right, vec); //右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> vec;
traversal(root, vec);
return vec;
}
1.1.2 中序遍历
void traversal(TreeNode* curr, vector<int> &vec) {
if(curr == nullptr) return; //递归终止条件
traversal(curr -> left, vec); //左
vec.push_back(curr -> val); //中,处理节点
traversal(curr -> right, vec); //右
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> vec;
traversal(root, vec);
return vec;
}
1.1.3 后序遍历
void traversal(TreeNode *curr, vector<int> &vec) {
if(curr == nullptr) return; //递归终止条件
traversal(curr -> left, vec); //左
traversal(curr -> right, vec); //右
vec.push_back(curr -> val); //中,处理节点
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> re;
traversal(root, re);
return re;
}
1.2 迭代法
迭代法用栈来模拟递归。
1.2.1 前序遍历
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st; //保存节点
vector<int> re; //保存结果
if(root) st.push(root); //将非空根节点入栈
while(!st.empty()) {
TreeNode *curr = st.top();
re.push_back(curr -> val); //中,处理节点
st.pop();
if(curr -> right) st.push(curr -> right); //右
if(curr -> left) st.push(curr -> left); //左
} //按右左顺序入栈,出栈时才能变为左右顺序
return re;
}
1.2.2 中序遍历
先左节点走到底,再进行其它操作。
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> re;
TreeNode *cur = root;
while(cur != nullptr || !st.empty()) {
if(cur != nullptr) {
st.push(cur);
cur = cur -> left; //左
} else {
cur = st.top();
st.pop();
re.push_back(cur -> val); //中,处理节点
cur = cur -> right; //右
}
}
return re;
}
1.2.3 后序遍历
后序遍历顺序是左右中,前序是中左右,故只需要稍稍修改前序代码为中右左,最后再反转即可得到左右中,即后序遍历。
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> vec;
if(root) st.push(root);
while(!st.empty()) {
TreeNode *cur = st.top();
st.pop();
vec.push_back(cur -> val); //中
if(cur -> left != nullptr) st.push(cur -> left); //左
if(cur -> right != nullptr) st.push(cur -> right); //右
} //入栈顺序为左右,出栈顺序为右左
reverse(vec.begin(), vec.end()); //反转
return vec;
}
1.3 统一的迭代法
统一的迭代法也是通过栈来实现的,其核心思想如下:
- 第一次访问栈中某节点时不记录其值,而是通过某种方法进行标记,并将其子节点加入栈中;
- 第二次访问该节点时记录其值并使其出栈。
通过标记将访问节点并使其子节点入栈的过程和记录节点的过程分离,这样就能实现三种迭代遍历的统一,区分不同遍历顺序只需要修改子节点入栈时的顺序即可。
这里的标记方法是在访问过的节点后面入栈一个空节点。也可以用其它标记方法,比如这里
1.3.1 前序遍历
入栈顺序是右左中,出栈顺序是中左右。
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> re;
if(root) st.push(root);
while(!st.empty()) {
TreeNode* cur = st.top();
if(cur != nullptr) { //不是空节点,说明第一次访问
st.pop(); //先出栈,方便调整顺序
if(cur -> right) st.push(cur -> right); //右
if(cur -> left) st.push(cur -> left); //左
st.push(cur); //中
st.push(nullptr); //用空节点标记该第一次访问的节点
} else { //是空节点,说明空节点后面那个节点是第二次访问,可以记录值了
st.pop(); //先将空节点出栈
re.push_back(st.top() -> val); //记录值
st.pop(); //将节点出栈
}
}
return re;
}
1.3.2 中序遍历
大体和前序相同,但入栈顺序为右中左,出栈顺序为左中右。
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> re;
if(root) st.push(root);
while(!st.empty()) {
TreeNode* cur = st.top();
if(cur != nullptr) {
st.pop(); //先出栈,方便调整顺序
if(cur -> right) st.push(cur -> right); //右
st.push(cur); //中
st.push(nullptr); //用空节点标记
if(cur -> left) st.push(cur -> left); //左
} else {
st.pop();
re.push_back(st.top() -> val);
st.pop();
}
}
return re;
}
1.3.3 后序遍历
大体和前序相同,但入栈顺序为中右左,出栈顺序为左右中。
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> re;
if(root) st.push(root);
while(!st.empty()) {
TreeNode *cur = st.top();
if(cur != nullptr) {
st.pop();
st.push(cur); //中
st.push(nullptr);
if(cur -> right) st.push(cur -> right); //右
if(cur -> left) st.push(cur -> left); //左
} else {
st.pop();
re.push_back(st.top() -> val);
st.pop();
}
}
return re;
}
二、广度优先遍历
leetcode题目:
102.二叉树的层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> qt;
vector<vector<int>> re; //二维数组存放最终结果
if(root) qt.push(root);
while(!qt.empty()) {
int size = qt.size(); //记录该层节点的数量
vector<int> vec; //存放该层节点的值
for(int i = 0; i < size; i++) { //依次处理该层节点,并将它们的子节点入队列尾
TreeNode *cur = qt.front();
vec.push_back(cur -> val); //处理节点,记录其值
qt.pop(); //节点出栈
if(cur -> left) qt.push(cur -> left); //左子节点入队列
if(cur -> right) qt.push(cur -> right); //右子节点入队列
} //循环结束刚好处理完一层节点,此时队列中的剩余节点为下一层的全部节点
re.push_back(vec);
}
return re;
}