二叉树的前序遍历
思想1:
- 从根节点开始遍左孩子,遍历到的每一个左孩子按照顺序放到栈中,并放到前序队列中,直到没有左孩子。
- 然后判断栈顶节点是否有右孩子,若有右孩子则将栈顶结点出栈,将右孩子入栈跳到1,此时右孩子就是右子树的根节点;若没有右孩子,则出栈,找到新的栈顶元素,跳到2的起始位置。直至栈为空。(这样会出现一个问题,步骤二中不是)
方法1:
/**
* 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){
stack<pair<TreeNode*, bool>> treeStack;
treeStack.emplace(make_pair(root, true));
while(!treeStack.empty()){
while (treeStack.top().second && treeStack.top().first->left) {
treeStack.top().second = false;
res.push_back(treeStack.top().first->val);
treeStack.emplace(make_pair(treeStack.top().first->left, true));
}
if(treeStack.top().second){
res.push_back(treeStack.top().first->val);
}
if(treeStack.top().first->right){
TreeNode * tmp = treeStack.top().first->right;
treeStack.pop();
treeStack.emplace(make_pair(tmp, true));
}
else{
treeStack.pop();
}
}
}
return res;
}
};
方法2:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if(NULL == root)
{
return res;
}
stack<TreeNode*> s;
TreeNode* node = root;
while(!s.empty() || NULL != node)
{
while (NULL != node) {
res.emplace_back(node->val);
s.emplace(node);
node = node->left;
}
node = s.top()->right;
s.pop();
}
return res;
}
};
方法二相较于方法一,更简洁更清楚。它们的思想是一致的,但是在处理最后一个节点的右孩子时不同。
思想二:
- 借助栈的特性,把根节点的右左孩子先后压到栈中。
-
这样左孩子为栈顶元素先出栈,跳到1。
class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> res; if(NULL == root) { return res; } stack<TreeNode*> s; s.emplace(root); while(!s.empty()) { TreeNode* node = s.top(); s.pop(); res.emplace_back(node->val); if(NULL != node->right) { s.emplace(node->right); } if(NULL != node->left) { s.emplace(node->left); } } return res; } };
二叉树的中序遍历
思想:
1.从根节点开始遍历左孩子,把经过的左孩子都放到栈中,但是在此过程中不把元素加到中序队列中,直至没有左孩子。
2.将栈顶元素出栈,加入到中序队列中,然后判断该该栈顶元素是否有右孩子,若有右孩子跳转1.否则跳转2起始位置,直至栈空。
方法1:
/**
* 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(NULL == root)
{
return res;
}
stack<TreeNode*> s;
TreeNode* node = root;
while(!s.empty() || NULL != node)
{
while(NULL != node)
{
s.emplace(node);
node = node -> left;
}
node = s.top();
s.pop();
res.emplace_back(node->val);
node = node->right;
}
return res;
}
};
方法2:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if(root != NULL){
stack<pair<TreeNode*, bool>> treeStack;
treeStack.emplace(make_pair(root, true));
while(!treeStack.empty()){
while (treeStack.top().second && (treeStack.top().first)->left) {
treeStack.top().second = false;
treeStack.emplace(make_pair((treeStack.top().first)->left, true));
}
res.push_back((treeStack.top().first)->val);
if ((treeStack.top().first)->right) {
TreeNode* tmp = (treeStack.top().first)->right;
treeStack.pop();
treeStack.emplace(make_pair(tmp, true));
}
else{
treeStack.pop();
}
}
}
return res;
}
};
方法1相较于方法2,更简洁更清楚。它们的思想是一致的,但是在处理最后一个节点的右孩子时不同。方法1借用临时变量node解决了每次循环必须要经历的寻找左子树环节。
二叉树的后序遍历
思想:
- 从根节点开始遍历左孩子,把经过的左孩子都放到栈中,但是在此过程中不把元素加到中序队列中,直至没有左孩子。
- 判断栈顶元素是否有右孩子,若有右孩子跳到1,否则将栈顶元素出栈,并加入到后序队列中,跳到2的起始位置。
方法1:
/**
* 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> postorderTraversal(TreeNode* root) {
vector<int> res;
if(NULL == root)
{
return res;
}
stack<TreeNode*> s;
TreeNode* node = root;
while(!s.empty() || NULL != node)
{
while(NULL != node)
{
s.emplace(node);
node = node -> left;
}
node = s.top();
if(NULL == node->right)
{
s.pop();
res.emplace_back(node->val);
node = NULL;
}
else
{
node = node->right;
s.top()->right = NULL;
}
}
return res;
}
};
方法2:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root != NULL){
stack<pair<TreeNode*, int>> treeStack;
treeStack.emplace(make_pair(root, 0));
while(!treeStack.empty()){
while (treeStack.top().second == 0 && treeStack.top().first->left) {
treeStack.top().second = 1;
treeStack.emplace(make_pair(treeStack.top().first->left, 0));
}
if(treeStack.top().second != 2 && treeStack.top().first->right){
treeStack.top().second = 2;
treeStack.emplace(make_pair(treeStack.top().first->right, 0));
}
else{
res.push_back(treeStack.top().first->val);
treeStack.pop();
}
}
}
return res;
}
};
方法3:
class Solution {
public:
vector<int> postorderTraversal(TreeNode *root) {
vector<int> res;
if (root == nullptr) {
return res;
}
stack<TreeNode *> stk;
TreeNode *prev = nullptr;
while (root != nullptr || !stk.empty()) {
while (root != nullptr) {
stk.emplace(root);
root = root->left;
}
root = stk.top();
stk.pop();
if (root->right == nullptr || root->right == prev) {
res.emplace_back(root->val);
prev = root;
root = nullptr;
} else {
stk.emplace(root);
root = root->right;
}
}
return res;
}
};
方法3和方法1的区别是:方法1改变了二叉树原有的连接,方法3用了更巧妙的临时变量prev,判断该节点的右孩子是否已被访问过。
思想2:
先序遍历是中左右,后序遍历是左右中,那么把先序遍历转换成中右左,再把得到的最终序列反转。
方法1:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left); // 相对于前序遍历,这更改一下入栈顺序 (空节点不入栈)
if (node->right) st.push(node->right); // 空节点不入栈
}
reverse(result.begin(), result.end()); // 将结果反转之后就是左右中的顺序了
return result;
}
};
方法2:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(NULL == root)
{
return res;
}
stack<TreeNode*> s;
TreeNode* node = root;
while(!s.empty() || NULL != node)
{
while (NULL != node) {
res.emplace_back(node->val);
s.emplace(node);
node = node->right;
}
node = s.top()->left;
s.pop();
}
reverse(res.begin(), res.end());
return res;
}
};