二叉树的递归绝对算不上难,但是非递归就要难一些,我们分别来看一看如何非递归进行前中后序遍历。
说在前边:
我们需要借助栈以及我们会以同一种大思路进行遍历,方便理解。
这种大思路就是先将左路节点入栈,找右子树
细节无非就是将栈中元素弹出与将二叉树的元素压入vector的时机不同
二叉树的前序遍历:
思路:
代码实现:
/**
* 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) {
typedef TreeNode Node;
Node* cur = root;
vector<int> ret;
stack<Node*> st;
while(cur)
{
// 压入左路节点
while(cur)
{
st.push(cur);
ret.push_back(cur->val);
cur = cur->left;
}
// 寻找右子树
while(!st.empty())
{
Node* top = st.top();
st.pop();
if(top->right)
{
cur = top->right;
break;
}
}
}
return ret;
}
};
这里的代码实现也是有一些细节的,首先对于压入左路节点没什么好说的,
重点是寻找右子树,我们的判断条件是栈是否为空,也就是说,我们的寻找右子树的这个循环有两种结束方式,
其一是找到了右子树,其二是当前栈中节点都没有右子树,当找到右子树我们重复步骤,否则就代表完成遍历了
二叉树的中序遍历:
思路:
中序与前序一致,注意:此时是在栈pop时进行压入节点。
代码实现:
/**
* 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) {
typedef TreeNode Node;
Node* cur = root;
vector<int> ret;
stack<Node*> st;
while(cur)
{
// 压入左路节点
while(cur)
{
st.push(cur);
cur = cur->left;
}
// 寻找右子树
while(!st.empty())
{
Node* top = st.top();
ret.push_back(top->val);
st.pop();
if(top->right)
{
cur = top->right;
break;
}
}
}
return ret;
}
};
二叉树的后序遍历:
后序的细节多了一丢丢,但是无伤大雅
思路:
代码实现:
/**
* 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) {
typedef TreeNode Node;
Node* cur = root;
vector<int> ret;
stack<Node*> st;
Node* tmp = nullptr;
while(cur)
{
while(cur)
{
st.push(cur);
cur = cur->left;
}
while(!st.empty())
{
Node* top = st.top();
if(!top->right)
{
st.pop();
tmp = top;
ret.push_back(top->val);
}
else
{
if(top->right == tmp)
{
ret.push_back(top->val);
st.pop();
tmp = top;
}
else
{
cur = top->right;
break;
}
}
}
}
return ret;
}
};
其实细心的同学也发现,这段代码可以更改的更优雅一些,因为最后一个while循环中有一部分代码被重复利用,可以将这两种情况合二为一,但是不容易理解,但是重点不在于优不优雅,而是我是使用一个临时变量tmp来记录的,进行判断是否遍历过当前节点,可以画图感受一下哦,
更重要的是tmp要定义在最外部,否则每次循环都会更改tmp那可就酿成大祸了。
此篇文章到此为止~