二叉树的迭代遍历
前序遍历
假如你出生在皇室,你们家有皇位继承,需要排继承顺序,江山总得有人继承。当前:包括皇帝在内,总共有7个人,可以继承皇位。
突然敌人来犯,7个人谁都可能会死,所有人投票决定按照【前序遍历】的顺序继承皇位。
定义:左孩子——皇子(孙) 右孩子——公主
首先是儿子2继承,儿子2死后是孙子4,孙子4死后是孙女5。
很不幸,儿子2这一支死完了,轮到了公主3这一支,公主3上位。
又很不幸,公主3 go die,王爷6上位,6死了,郡主7上位。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root)
{
vector<int> res;
if (root == nullptr)
{
return res;
}
stack<TreeNode*> stk;
TreeNode* node = root;
while (!stk.empty() || node != nullptr)
{
while (node != nullptr)
{
res.emplace_back(node->val);
stk.emplace(node);
node = node->left;
}
node = stk.top();
stk.pop();
node = node->right;
}
return res;
}
};
//代码怎么写,当前结点为空 并且栈也为空
while (node != nullptr || !stk.empty())
{
while(node! = nullptr) // 寻找最左的孩子 也就是嫡皇子
{
result.insert(node->val); //打印当前元素 继承皇位
stk.push(node); //记录当前元素 相当于族谱一样的
node = node ->left;
}
//最左的孩子 没有儿子 相当于嫡皇子没有儿子 那就翻记录【stack】看看有没有公主 同样以后还是要
//找左孩子
node = stk.top();
stk.pop();
node= node->right;
}
class Solution {
public:
vector<int> preorderTraversal(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->right) st.push(node->right); // 右(空节点不入栈)
if (node->left) st.push(node->left); // 左(空节点不入栈)
}
return result;
}
};
//作者:代码随想录
//链接:https://leetcode.cn/problems/binary-tree-postorder-traversal/solutions/367420/bang-ni-dui-er-cha-shu-bu-zai-mi-mang-che-di-chi-t/
//来源:力扣(LeetCode)
//著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
中序遍历
中序遍历是什么? 左根右
较前序遍历,有什么不同? 先处理左子树,再处理当前结点,最后处理右结点。
为什么需要栈? 给定的参数,肯定是从根结点开始, 程序遍历原始参数是 根左, 想要达到左根的结果,使用栈比较方便。
依旧一路向左? 因为我们人在遍历二叉树的时候 ,很自然的就是找最左的
有右孩子
[1,2,4,5,3,6,7]
遍历到2时,2是个根,左根右【4,2,5】 有右孩子5,切到5上,以5为根继续【左根右】
最终结果:【[4,2,5,1,6,3,7]】
没有右孩子
遍历到2时,[1,2,5,3,6,7] 左根右【4,2,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<int> inorderTraversal(TreeNode* root)
{
vector<int> result;
stack<TreeNode*> sta;
TreeNode* cur = root;
if(root == nullptr)
return result;
while(cur!= nullptr || !sta.empty())
{
while (cur!= nullptr)
{
sta.push(cur);
cur = cur->left;
}
cur = sta.top();
sta.pop();
result.push_back(cur->val); //打印元素 移到这里? 为什么是这里, 因为下一步要切到 cur->right 上。
cur = cur->right;
}
return result;
}
};
后序遍历
注意到,所有的子树,最后一个结点就是子树的根结点。
- 先将根结点入栈,输出到结果数组中
- 左子树头入栈,右子树头入栈,
- 弹出栈顶元素,输出到结果数组中,
- 第2步和 第3步 循环 直至所有的结果输出【辅助栈为空】
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root)
{
vector<int> result; // 存储后序遍历结果
stack<TreeNode*> stk; // 辅助栈
// 如果根节点为空,则直接返回空结果
if (root == nullptr) return result;
// 将根节点入栈
stk.push(root);
// 当栈不为空时进行遍历
while (!stk.empty())
{
TreeNode* curr = stk.top(); // 取出栈顶节点
stk.pop();
// 将当前节点值插入到结果的头部,实现倒序
result.insert(result.begin(), curr->val);
// 如果当前节点的左子树不为空,则将左子树入栈
if (curr->left) stk.push(curr->left);
// 如果当前节点的右子树不为空,则将右子树入栈
if (curr->right) stk.push(curr->right);
}
return result;
}
};
另一种想法
能不能尽量统一写法? 就记住前(后)序遍历,在前(后)序遍历的基础上调整;
前序遍历:根左右
后序遍历: 左右根
所有人,接触到这个问题时,很自然会想过,前序遍历 逆序是不是后续遍历? 答案是肯定的 不是。
前序逆序: 右左根
与预期 左右根差一点。调整下前序遍历,左右的处理顺序就可以有后序遍历的逆序~
//前序遍历
class Solution {
public:
vector<int> preorderTraversal(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->right) st.push(node->right); // 右(空节点不入栈)
if (node->left) st.push(node->left); // 左(空节点不入栈)
}
return result;
}
};
//后序遍历
//上面的没有什么不同
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;
}
};