144. 二叉树的前序遍历 - 力扣(LeetCode)
145. 二叉树的后序遍历 - 力扣(LeetCode)
94. 二叉树的中序遍历 - 力扣(LeetCode)
看题。用递归,前中后序遍历。
递归就太简单了,想好出口。宏观到围观,和谐之美。
/**
* 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 inorderTraversal(TreeNode* root) {
TreeNode* far = root;
vector result;
if (far == NULL) return result;
// result.push_back(root->val); // 前序,先push父节点
vector result_left = inorderTraversal(root->left);
result.insert(result.end(), result_left.begin(), result_left.end());
result.push_back(root->val); // 中序,push完左边的,再push父节点
vector result_right = inorderTraversal(root->right);
result.insert(result.end(), result_right.begin(), result_right.end());
// result.push_back(root->val); // 后序,push完左边和右边的,最后push父节点
return result;
}
};
略。
禁止递归。
用栈来表示递归。
1. 前序遍历
比较简单,每次取出来栈顶的,就直接push到result中。先压右孩子,再压左孩子。因为每次要先考虑左孩子。
class Solution {
public:
vector preorderTraversal(TreeNode* root) {
stack stc;
vector result;
if (root == NULL) return result;
stc.push(root);
while (!stc.empty()) {
TreeNode* cur = stc.top();
result.push_back(cur->val);
stc.pop();
if (cur->right != NULL) stc.push(cur->right);
if (cur->left != NULL) stc.push(cur->left);
}
return result;
}
};
2. 后序遍历
熟悉后续遍历就知道,它是“左右父”的顺序遍历。用栈的话,明显不如前序遍历简单。但是,比较巧妙的是,后序遍历反过来就是“父右左”的顺序,这和前序遍历“父左右”,事实上异曲同工。(可以举例证实)
于是,后序遍历的迭代法就是,先伪前序遍历“父右左”,然后反转数组即可。
/**
* 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 postorderTraversal(TreeNode* root) {
stack std;
vector result;
if (root == NULL) return result;
std.push(root);
// TreeNode* pre = root;
while (!std.empty()) {
TreeNode* cur = std.top();
std.pop();
if (cur->left != NULL) std.push(cur->left);
if (cur->right != NULL) std.push(cur->right);
result.push_back(cur->val);
}
reverse(result.begin(), result.end());
return result;
}
};
3. 中序遍历
比较难了。从头捋一遍。
遍历二叉树涉及到两个操作,对于同一个节点,一个是要访问:这个节点是否为NULL,另一个是记录:把其数值存入result数组中。
对于前序和后序,都可以用:同一个节点访问和记录两个操作同时进行的代码解决。但是中序就不行了,访问某节点时,并不能同时记录该节点。
进一步说明,在前序和后续遍历中,从栈中pop出来的节点,既要继续访问其子节点(push),又要记录其本身数值(result.push_back)。
那么,在中序遍历中,从栈中pop出来的节点,是否可以同时访问其子节点并记录其本身数值呢?
显然不行,有矛盾,left还没被访问,怎么能记录其本身呢?这不符合中序遍历的逻辑。
故,从栈中pop出来的节点,并不适合访问leat,适合记录然后访问right。
代码逻辑是,先持续访问left到底(push到栈中),当NULL了,从栈中pop一个,记录,然后访问right(push到栈中)。
抽象一点描述就是:
1. 横冲直撞left到底。
2. 碰到底(NULL)了,就退回一步(pop),记录并从right拐一步。
3. 循环1~2.
/**
* 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 preorderTraversal(TreeNode* root) {
stack stc;
vector result;
if (root == NULL) return result;
stc.push(root);
while (!stc.empty()) {
TreeNode* cur = stc.top();
result.push_back(cur->val);
stc.pop();
if (cur->right != NULL) stc.push(cur->right);
if (cur->left != NULL) stc.push(cur->left);
}
return result;
}
};
略。
是否有非递归,但统一代码风格的迭代解法?
前中后序遍历,迭代法,最大的不同就是同一个节点的访问和记录错位。即,利用栈来实现遍历时,从栈中pop出来的节点,需要考虑是否要访问该节点的子节点,以及是否要记录该节点的数值。前序,两个操作可以同时进行;中序和后序不能同时。
解决方法是,标记需要记录的节点。可以在需要记录的节点前,压入NULL到栈中。
循环中,每个栈顶的非空节点,都进行访问,然后根据前中后,考虑把该节点再以什么顺序压入。前,先压右,再压左,最后压自己;中,先右,再自己,后左;后,先自己,再右,后左。重新压入自己时,意味着访问结束,则再压入NULL节点表示只剩访问。
遇到空节点,则记录空间点底下的那个。
/**
* 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 postorderTraversal(TreeNode* root) {
vector result;
stack std;
if (root == NULL) return result;
std.push(root);
while (!std.empty()) {
TreeNode* cur = std.top();
if (cur != NULL) {
std.pop();
std.push(cur); ///后
std.push(NULL); ///
if (cur->right != NULL) std.push(cur->right);
// std.push(cur); ///中
// std.push(NULL); ///
if (cur->left != NULL) std.push(cur->left);
// std.push(cur); ///前
// std.push(NULL); ///
} else {
std.pop();
cur = std.top();
std.pop();
result.push_back(cur->val);
}
}
return result;
}
};