二叉树的遍历--非递归实现

leetcode中有这么一道题,非递归来实现二叉树的遍历。

二叉树的后序遍历顺序为,root->left, root->right,
root,因此需要保存根节点的状态。显然使用栈来模拟递归的过程,但是难点是怎么从root->right转换到root。

方法1:

对于节点p可以分情况讨论

1. p如果是叶子节点,直接输出

2. p如果有孩子,且孩子没有被访问过,则按照右孩子,左孩子的顺序依次入栈

3. p如果有孩子,而且孩子都已经访问过,则访问p节点

如何来表示出p的孩是否都已经访问过了呢?

最暴力的方法就是对每个节点的状态进行保存,这么做显然是可以的,但是空间复杂度太大了。

我们可以保存最后一个访问的节点last,如果满足 (p->right==NULL && last ==p->left)
|| last=p->right,那么显然p的孩子都访问过了,接下来可以访问p

代码如下


1 vector<int> postOrder(TreeNode *root)
2 {
3 vector<int> res;
4 if(root == NULL) return res;
5
6 TreeNode *p = root;
7 stack<TreeNode *> sta;
8 TreeNode *last = root;
9 sta.push(p);
10 while (!sta.empty())
11 {
12 p = sta.top();
13 if( (p->left == NULL && p->right == NULL) || (p->right == NULL && last == p->left) || (last == p->right) )
14 {
15 res.push_back(p->val);
16 last = p;
17 sta.pop();
18 }
19 else
20 {
21 if(p->right)
22 sta.push(p->right);
23 if(p->left)
24 sta.push(p->left);
25 }
26
27 }
28
29
30 return res;
31 }

方法2:
其实我们希望栈中保存的从顶部依次是root->left, root->right, root,当符合上面提到的条件时,就进行出栈操作。有一种巧妙的方法可以做到,先上代码


1 vector<int> postOrder(TreeNode *root)
2 {
3 vector<int> res;
4 if(root == NULL) return res;
5
6 TreeNode *p = root;
7 stack<TreeNode *> sta;
8 sta.push(p);
9 sta.push(p);
10 while(!sta.empty())
11 {
12 p = sta.top(); sta.pop();
13 if(!sta.empty() && p==sta.top())
14 {
15 if(p->right) sta.push(p->right), sta.push(p->right);
16 if(p->left) sta.push(p->left), sta.push(p->left);
17 }
18 else
19 res.push_back(p->val);
20 }
21
22 return res;
23 }

对于每个节点,都压入两遍,在循环体中,每次弹出一个节点赋给p,如果p仍然等于栈的头结点,说明p的孩子们还没有被操作过,应该把它的孩子们加入栈中,否则,访问p。也就是说,第一次弹出,将p的孩子压入栈中,第二次弹出,访问p。
 
 

时间: 2024-10-25 00:32:26

二叉树的遍历--非递归实现的相关文章

二叉树的遍历(非递归)

1 //二叉树的先序遍历(非递归) 2 public void PreOrderTraverse() 3 { 4 BiTNode p = this.root; 5 Stack stack = new Stack(10000); 6 7 while(!stack.isEmpty || p != null) 8 if(p != null) 9 { 10 if(p.rchild != null) 11 stack.push(p.rchild); 12 System.out.print(p.data +

二叉树前序遍历非递归写法

前序遍历非递归依靠栈实现,相对来说比较简单,先来用手写模拟一下基本就能知道怎么写了 据此可得如下代码 void preOrder_stack(BiTree T){ printf("\n非递归先序遍历结果:\n"); initStack(&sqStack); BiTree p=T; push(&sqStack,p); while(!stackEmpty(sqStack)){ pop(&sqStack,&p); printf("%d ",

最容易理解的二叉树后续遍历非递归java实现

后续遍历要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈.如果P不存在左孩子和右孩子,则可以直接访问它:或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点.若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问. java private static void postOrderNonRecursiveEasily(Node root) {

二叉树前序、中序、后序遍历非递归写法的透彻解析

前言 在前两篇文章二叉树和二叉搜索树中已经涉及到了二叉树的三种遍历.递归写法,只要理解思想,几行代码.可是非递归写法却很不容易.这里特地总结下,透彻解析它们的非递归写法.其中,中序遍历的非递归写法最简单,后序遍历最难.我们的讨论基础是这样的: //Binary Tree Node typedef struct node { int data; struct node* lchild; //左孩子 struct node* rchild; //右孩子 }BTNode; 首先,有一点是明确的:非递归

二叉树先序、中序、后续遍历非递归

1 ** 2 * 二叉树先序遍历非递归 3 * @param root 4 */ 5 public void preOrder_no_recursive(TreeNode root){ 6 if(root == null) return; 7 8 Stack<TreeNode> stack = new Stack<>(); 9 stack.add(root); 10 while(!stack.isEmpty()){ 11 TreeNode tn = stack.pop(); 12

二叉树的遍历(递归、非递归)

1 public class BinTree { 2 private char date; 3 private BinTree lchild; 4 private BinTree rchild; 5 6 public BinTree(char c) { 7 date = c; 8 } 9 10 // 先序遍历递归 11 public static void preOrder(BinTree t) { 12 if (t == null) { 13 return; 14 } 15 System.ou

二叉树的中序、先序、后序遍历非递归遍历算法(使用堆栈,用循环实现)

1 typedef struct TreeNode *BinTree; 2 typedef BinTree Position; 3 struct TreeNode{ 4 ElementType Data; 5 BinTree Left; 6 BinTree Right; 7 }; 8 BinTree BT; 9 void InOrderTraversal(BinTree BT)//中序遍历非递归遍历算法(使用堆栈,用循环实现) 10 { 11 BinTree T=BT; 12 Stack S=C

二叉树的遍历,递归和非递归

import java.util.ArrayDeque; import java.util.Stack; class TreeNode { public int val; public TreeNode left; public TreeNode right; public TreeNode(int val) { this.val = val; } } public class BinaryTree { //先序遍历递归 public static void preOrder(TreeNode

前序中序后序遍历非递归实现

#include<iostream> #include<vector> #include<stack> #include<string> #include<algorithm> #include<numeric> using namespace std; class node{ public: int val; node* left; node* right; node():val(0),left(NULL),right(NULL){