后续遍历二叉树的非递归算法

乔不思 2013-10-19 04:25:13
加精
1.将左边的节点先压入栈,
2.将栈中的 节点作为根节点,判断他的有子树是否为空(叶子节点),或者已经遍历过,如果满足则执行,否则,执行第三步。
3.遍历有子树


public static void LaGet1(TreeModels root){//后续遍历(非递归),基于栈
TreeStack ts=new TreeStack();//这个是栈
TreeModels root1=null;//这个保存前一个遍历过得节点
while(root!=null||ts.index!=0){
while(root!=null){

ts.push(root);//栈的push操作
//System.out.println(root.getData());
root=root.getLeft();
}
if(ts.index!=0){

root=ts.pop();//退栈操作


if(root.getRight()==null||root.getRight()==root1){

System.out.print(root.getData()+" ");
root1=root;
root=null;
//System.out.println("root1: "+root1.getData());
}

else{
root=root.getRight();

}

}

}
}



按上面的思路我写出了代码,但是为啥最终得到的 是叶子节点,,,高手给看看我的 思路对不对,要是对,那我的代码那里错了? 大家帮忙给我看看。。
...全文
6546 85 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
85 条回复
切换为时间正序
请发表友善的回复…
发表回复
wangsufu77 2014-02-12
  • 打赏
  • 举报
回复
这个用得到?
乔不思 2013-12-22
  • 打赏
  • 举报
回复
引用 83 楼 u012937966 的回复:
引用 70 楼 u012575652 的回复:
一定要认真学习
同意70楼,如果最后一个if不成立(即root.getright()不等于空),则应再将此root节点压入栈,此节点要等到其右子节点被遍历后才能被遍历。
我能说,我已经错过了学习数据结构的年龄了么
notadiot 2013-12-21
  • 打赏
  • 举报
回复
引用 70 楼 u012575652 的回复:
一定要认真学习
同意70楼,如果最后一个if不成立(即root.getright()不等于空),则应再将此root节点压入栈,此节点要等到其右子节点被遍历后才能被遍历。
  • 打赏
  • 举报
回复
一直没耐心好好看帖子
bazingagain 2013-11-15
  • 打赏
  • 举报
回复
学习了
ztl_ 2013-11-14
  • 打赏
  • 举报
回复
值得学习,看来下面得扩展下。
初心还在 2013-11-13
  • 打赏
  • 举报
回复
看的都晕了,,,虽然学过
lhw7791086 2013-11-13
  • 打赏
  • 举报
回复
云渊阁 2013-11-07
  • 打赏
  • 举报
回复
猿猿猿媛 2013-11-06
  • 打赏
  • 举报
回复
刚学2叉树
另一花生 2013-11-02
  • 打赏
  • 举报
回复
看你写的东西,我才知道自己好无知==
Hubery- 2013-10-30
  • 打赏
  • 举报
回复
受教了!
花含 2013-10-29
  • 打赏
  • 举报
回复
都是高手呀
Damn_boy 2013-10-28
  • 打赏
  • 举报
回复
就是要有一个标志位来标示当前节点是否已经遍历过左右子树了 不然就是死循环

void POSTORDER(binary_tree *root)
{
 binary_tree *stack[MAX_STACK_SIZE];

   while( root || esp != -1)
   {
      if(root&& !root->flag)
      {
           push(&esp,stack,root);
         root=root->left_child;
         continue;
      }

      if(esp == -1)
      break;
      //SIGN:

    root = pop(&esp,stack);
     

    if( !root->flag )
      {
         root->flag=1;
         push(&esp,stack,root);
         root=root->right_child;
      }
      else
      {
         printf("%d\n",root->data);

       // goto SIGN
      }
   }

}
从递归版本的代码来分析如何得到这个非递归版本 后序遍历,递归
void postorder(binary_tree *root)

{

  if( root)

  {

     postorder(root -> left_child);

     postorder(root -> right_child);

     printf("Node\n");

  }

}
  简要的分析一下这个递归函数。   函数调用的时候  把 1.访问右子树的操作              2.和访问本节点数据域的操作先放在一边             可以理解为 将这两个操作压栈。   逐步之下,直到遇到左子树为空的情况,弹出对应操作。       1     2   3    4 5 6 7   。 。。 。。 。 。 。   当前节点     压栈操作   1        访问3  输出1   2        访问5  输出2   4        访问。  输出4    。           当到达。的时候, 没有后继操作       于是弹出堆栈里的参数,以便做对应的操作。   弹出访问。 没有后继操作   弹出输出4 printf("NODE"); //这时 4的左右子树都已经访问完毕   弹出访问5 5作为一个新的节点 产生一个压栈的动作 : 访问。 输出5   当前位置。 没有操作   弹出。   没有操作   弹出输出5   这样 4和5作为2的子树, 已经访问完毕,现在可以访问2.   否则 按照如上的操作继续下去, 弹出2 又产生 将 访问5和输出2的操作 压栈的东西 ,必然进入死循环。   于是想要设置一个标志位 当2的左右子树的访问完毕的时候, 标记一下 这时候弹出 输出2的操作。   以上压栈时的参数全为 指针 写成操作纯粹为了好理解。   大概可以这样。   当到达一个节点的时候, 将当前节点指针压栈。   当该节点的左子树访问完毕以后,该节点的节点指针必然出栈,但是该出栈动作只是为了寻找它的右子树。   所以还要将该节点指针重新进栈   关键就在这里, 这一进一出的操作,表示已经访问了这个节点的左右子树,下次在碰到这个节点的时候   弹出它 并且对它进行printf()操作。       为了便于标示这个动作, 我们给这个指针设置一个标记,或者说给这个节点设置一个标记。   typedef struct BINARY_TREE{     int flag;     BINARY_TREE *lp;     BINARY_TREE *rp;     int data;   }binary_tree;   结构中的flag用于标记 该节点的左右子树已成功访问。   对于没访问的flag默认为0;   访问成功的 flag设置为1;   这样就解决了死循环的问题。
xucong198949 2013-10-27
  • 打赏
  • 举报
回复
ts.push(root); root = root.getRight(); 试试这样OK不??
梁子123 2013-10-26
  • 打赏
  • 举报
回复
一定要认真学习
fengxing 2013-10-25
  • 打赏
  • 举报
回复
前来看看,受教了噶
yessigoal 2013-10-25
  • 打赏
  • 举报
回复
引用 40 楼 zhouren1314 的回复:
[quote=引用 39 楼 h2plus0 的回复:] 最主要的想法是把一个节点展开, 但放到stack中的时候需要记住这个节点有没有展开过

import java.util.Stack;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;

/**
 * post order access tree
 * http://www.devbeacon.com
 */
public class PostOrderAccessTree {

	static class StkData {
		public StkData(TreeNode node) {
			this.node = node;
			expanded = false;
		}
		TreeNode node;
		boolean expanded;
	}

	public static void post(TreeNode root) {
		if(root==null) return;
		Stack<StkData> stk = new Stack<StkData>();
		StkData d = new StkData(root);
		stk.push(d);
		
		while(!stk.empty()) {
			d = stk.peek(); // not pop !!
			if(d.expanded) {
				System.out.println(d.node);
				stk.pop();
			}
			else {
				d.expanded = true;

				for(int i=d.node.getChildCount()-1;i>=0;i--) {
					StkData t  = new StkData(d.node.getChildAt(i));
					stk.push(t);
				}
			}
		}
	}
	
	public static void main(String[] args) {
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("a");
		
		DefaultMutableTreeNode b = new DefaultMutableTreeNode("b");
		DefaultMutableTreeNode c = new DefaultMutableTreeNode("c");
		
		DefaultMutableTreeNode d = new DefaultMutableTreeNode("d");
		DefaultMutableTreeNode e = new DefaultMutableTreeNode("e");
		DefaultMutableTreeNode f = new DefaultMutableTreeNode("f");
		DefaultMutableTreeNode g = new DefaultMutableTreeNode("g");
		DefaultMutableTreeNode h = new DefaultMutableTreeNode("h");

		root.add(b);
		root.add(c);
		
		b.add(d); b.add(e);
		c.add(f); c.add(g);
		e.add(h);
		
		post(root);
	}
}
能告诉我 28行peek();是什么意思吗? 再一个,,看一下我的 思想对吗? 代码对吗?[/quote] peek()是查看栈顶元素
名字到底多长 2013-10-24
  • 打赏
  • 举报
回复
每次从栈里弹出节点要干两件事: 1 判断是否存在右子树并且利用上个节点的标识决定是直接访问这个节点还是将节点入栈继续遍历 2 为下次节点判断当前节点是否是下次节点的右子树。
名字到底多长 2013-10-24
  • 打赏
  • 举报
回复
后序相对于前序和中序最大的问题就是当你从栈里面取出一个节点时,如果有右子树且没有访问过的话,这个点要重新塞回stack。而前序和中序没有这个问题。前序在塞入栈的之前已经访问过了。中序从栈中取出来就是要访问的。 因此就是利用存在右子树且有没访问这个条件。每次一个节点从栈弹出时,如果栈还不为空并且栈顶元素的右子树为当前弹出的节点时,表明栈顶的元素的右子树已经访问过了因此标识下给下次出栈节点利用,如果没有访问过且存在右子树的话,则将节点入栈进入右子树遍历。lz可能忽视了这个。
加载更多回复(46)

81,122

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧