3道题目
144. 二叉树的前序遍历
94. 二叉树的中序遍历
145. 二叉树的后序遍历
解题理解
今天的题都是最普通的二叉树遍历,前序中序后序的原理和流程已经比较熟悉了,但实现方法并不一致,做题的时候基本都是凭感觉走,这次一共学到了三种写法,两种几乎模板化,还有一种需要变通,我个人倾向于同一迭代法,尽量不去用递归写法。
另外,三种实现方法中,只有一种是递归法,其他都是迭代法,其实迭代法做的就是模拟栈的过程,因为递归在底层的实现方式就是(递归)栈。既然是模拟栈的过程,那么顺序访问结点时,就不能像递归法那样符合原理流程那样访问了(即前序就顺序访问中左右,中序左中右,后续左右中),此时应该按栈先入后出访问结点,实现前中序遍历。
递归法
############144. 二叉树的前序遍历############
class Solution {
public:
void traversal(vector<int> &res, TreeNode* root){
if(root == nullptr){
return;
}
res.push_back(root->val);
traversal(res, root->left);
traversal(res, root->right);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
traversal(res, root);
return res;
}
};
############94. 二叉树的中序遍历############
class Solution {
public:
void traversal(vector<int> &res, TreeNode* root){
if(root == nullptr){
return;
}
traversal(res, root->left);
res.push_back(root->val);
traversal(res, root->right);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
traversal(res, root);
return res;
}
};
############145. 二叉树的后序遍历############
class Solution {
public:
void traversal(vector<int> &res, TreeNode* root){
if(root == nullptr){
return;
}
traversal(res, root->left);
traversal(res, root->right);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
traversal(res, root);
return res;
}
};
迭代法
############144. 二叉树的前序遍历############
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
if(root == nullptr) return res;
st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
res.push_back(node->val);
st.pop();
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
}
return res;
}
};
############94. 二叉树的中序遍历############
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root == nullptr) return res;
TreeNode* cur = root;
while(cur != nullptr || !st.empty()){
if(cur != nullptr){
st.push(cur);
cur = cur->left;
}else{
cur = st.top();
st.pop();
res.push_back(cur->val);
cur = cur->right;
}
}
return res;
}
};
############145. 二叉树的后序遍历############
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root == nullptr) return res;
stack<TreeNode*> st;
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;
}
};
统一迭代法
############144. 二叉树的前序遍历############
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> res;
if(root != NULL) st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
if(node!=NULL){
st.pop();
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
st.push(node);
st.push(NULL);
}else{
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
############94. 二叉树的中序遍历############
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root != nullptr) st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
if(node != nullptr){
st.pop();
if(node->right != nullptr) st.push(node->right);
st.push(node);
st.push(nullptr);
if(node->left != nullptr) st.push(node->left);
}else{
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
############145. 二叉树的后序遍历############
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
if(root != nullptr) st.push(root);
while(!st.empty()){
TreeNode* node = st.top();
if(node!=nullptr){
st.pop();
st.push(node);
st.push(nullptr);
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
}else{
st.pop();
node = st.top();
st.pop();
res.push_back(node->val);
}
}
return res;
}
};
三种方法里,我比较喜欢第三种统一写法的,并且里面设计的NULL标签很巧妙,但第三种也是不容易理解的,长时间不写,也容易忘,尤其是if、else后紧跟的两个pop(),也是因为这两个pop(),我个人感觉这个方法可能不如第二种复杂度低。
只能说三种方法各有好坏,递归易理解,容易记忆,但是递归复杂度一般较高;一般迭代每种遍历写法不一样不好理解,但效率高;统一迭代好理解,但需要熟练度,并且复杂度也不一定很低。