前序、中序、后序遍历二叉树递归与非递归实现
前序、中序、后序递归
非常简单,调整访问根节点的时机即可
void traverse(TreeNode* root){
if(!root) return; //递归出口
//cout << root->val <<endl; //前序
traverse(root->left);
//cout << root->val <<endl; //中序
traverse(root->right);
//cout << root->val <<endl; //后序
}
前序非递归
利用栈,注意先放入右孩子,再放入左孩子
void traverse(TreeNode* root){
if(!root) return;
stack<TreeNode*> s;
s.push(root);
while(!s.empty()){
TreeNode* curr=s.top();
s.pop();
cout << curr->val << endl;
if(curr->right) s.push(curr->right);
if(curr->left) s.push(curr->left);
}
}
中序非递归
利用栈,每一个结点都要先压入所有左孩子
- 使用curr=curr->right,是因为中序遍历先访问根节点再访问右孩子结点
- 如果curr->right==NULL,再回到循环开始,不会进入第二层循环,相当于上一次访问的根节点是这个访问结点的左孩子
void traverse(TreeNode* root){
stack<TreeNode*> s;
TreeNode* curr=root;
while(curr||!s.empty()){
while(curr){
s.push(curr);
curr=curr->left;
}
curr=s.top();
s.pop();
cout << curr->val << endl;
curr=curr->right;
}
}
后序非递归
和中序类似,利用栈,每一个结点都要先压入所有左孩子
在访问根节点之前,要判断是右孩子是否存在或上一个访问的结点是不是右孩子
- 如果右孩子存在并且上一个访问的不是右孩子,那么重新将根节点压入,右孩子结点进入循环
- 其他情况,都可以直接访问根节点
void traverse(TreeNode* root){
stack<TreeNode*> s;
TreeNode* pre=root,*curr=root;
while(curr||!s.empty()){
while(curr){
s.push(curr);
curr=curr->left;
}
curr=s.top();
s.pop();
if(curr->right&&pre!=curr->right){
s.push(curr);
curr=curr->right;
}
else {
cout << curr->val << endl;
pre=curr;//更新指针pre
curr=NULL;//访问完根节点,下一个要访问的结点从栈中取出。不取空值,又会继续找左孩子
}
}
return ans;
}