【无浪】二叉树拆解课堂一之三种非递归遍历


可能长代码大多人只会匆匆瞟一眼然后COPY一下看看输出结果吧。那就分解成短代码来一块一块详细解释一下吧。不过一般很复杂的程序都是由大量的各种简单的知识点组成的。


现在在网上看到的我需要的代码,如果有时间的话我会把它整个抄下来然后用笔去一行一行推。问我哪里来的时间.....当然是那些无聊的选修课了.......


void Tree::Non_Recursive_PreOrder(TreeNode*T)  //protected非递归先序遍历
	{
		/*——————————————————————————
	       	   首先进行p的输出。存储的内容基本上是右结点。
	    	遍历左边缘不断输出,然后转到右结点入栈,继续
	    	左边缘不断输出。等到再无左边缘的时候逆向输出
	    	所有右孩子。
		———————————————————————————*/
		stack<TreeNode*> s;
		TreeNode *p=T,*q;
		s.push(p);//把Root推入栈内
		while(!s.empty())//如果s不空
		{
			cout<<p->data;
			q=p->RightChild;
			if(q)s.push(q); //如果q(p的右孩子)不空则将q推入栈
			p=p->LeftChild;
			if(!p)         //如果p(p的左孩子)为空则回到(p的右孩子)
			{
				p=s.top();
				s.pop();
			}//if
		}//while
	}//Non_recursive_PreOrder


首先是先序遍历的流程

非递归先序遍历实现的步骤:

①首先定义一个<TreeNode*>类型的栈。

②定义两个指针变量p和q,p等于参数,即树的根节点;q用来存储右孩子。然后把p入栈。

③一旦栈不空

a.输出p的数值并看它的右孩子存不存在,存在就把它的右孩子推入栈内。

b.然后看左孩子是否为空,若为空则栈的首元素出栈(即最邻近的一个树节点的右孩子)赋值给p。






	void Tree::Non_Recursive_IndexOrder(TreeNode*T)  //protected非递归中序遍历
	{
		/*————————————————————————————
		       首先不断遍历左边缘但不输出只入栈,
	    	直到碰到NULL后(此时p=NULL)返回父结点输出父结点。
	    	然后转到右结点入栈,继续遍历左边缘不输出
	    	只入栈。一直编立到某个度为0的右结点的右孩子的时候
	    	结束一支分支的遍历。
	    	    另一支分支的遍历相同。这一支分支的遍历
	    	结束后中序遍历结束。
		—————————————————————————————*/
		stack<TreeNode*> s;
		TreeNode *p=T;
		s.push(NULL);
		while(1)
		{
			while(p)
			{
				s.push(p);         //栈是回溯法的主要工具
				p=p->LeftChild;
			}//while 遍历左边缘直到NULL
			if(!s.top())break;//如果栈到达栈底则跳出
			p=s.top();//p=NULL的时候返回其父结点或爷结点
			s.pop();//弹出父结点
			cout<<p->data;//输出父结点
			p=p->RightChild;//调用父结点的右孩子
		}//while
	}//Non_recursive_IndexOrder



非递归中序遍历步骤:

①定义栈,树指针结点,并将 NULL push进栈。如果不push个NULL的话   用while(!s.empty())会直接跳出函数,

②循环,如果p不为空则将p入栈然后p等于它的左孩子。一直遍历到 'a'  的左孩子的位置(即NULL)。

③跳出无限循环的条件,如果到达了栈底(NULL)就跳出无限循环。

④这个时候p的值为NULL,所以获得栈首元素(父节点'a')然后出栈。

⑤输出当前p的值。('a')

⑥p访问当前结点的右孩子。(如果有右孩子则会沿着右孩子的左孩子遍历并入栈,如果右孩子为空则会继续往上遍历父节点。)







	void Tree::Non_Recursive_PostOrder(TreeNode*T)  //protected非递归后序遍历
	{
		/*——————————————————————————
		  先进行左边缘遍历,入栈,并记载访问次数为1(tag=0)。
		  直到p=NULL,然后返回父结点,父结点访问次数为2(tag=1)。
		  p转到父结点的右孩子。
		  重复以上步骤。
		  如果栈顶结点被第三次访问,则输出该结点,弹出。
		———————————————————————————*/
		stack<TreeNode*> s;//用于存储树结点
		stack<bool>s1;//用于存储结点暂离状态
		TreeNode *p=T;
		s.push(NULL);//没有此句函数直接结束
		while(1)//如果s不空
		{
			while(p)
			{
				s.push(p);
				s1.push(false);
				p=p->LeftChild;
			}//while 用于存储左边缘树结点,全部暂离
			if(s1.top())
			{
				p=s.top();
				s1.pop();
				s.pop();
				cout<<p->data;
				p=NULL;
			}//if 第二次访问结点结点已待命,将结点和状态全部弹出,输出结点。令p=NULL,避免第四次读取结点。
			else
			{
				s1.pop();
				s1.push(true);
				p=s.top()->RightChild;
			}//else 如果结点是暂离,让其准备,当第二次碰见它时就输出。此时访问右孩子
			if(!s.top())break;//如果栈到达栈底则跳出
		}//while
	}//Non_recursive_PostOrder

(第一次访问结点入栈状态为false,第二次访问结点将状态改成true,第三次访问结点输出结点数据,避免出现第四次访问结点。)

(为什么是这样?访问父节点的时候设置状态为false,访问左孩子回到父节点状态改成true,从右孩子回到父节点的时候输出父节点,共三次。)
非递归后序遍历的步骤:

①定义两个栈,第一个栈类型为<TreeNode*> 第二个栈类型为<bool>,以及树节点指针p,将NULL push进栈。

②循环,如果p不为空,则(树节点栈)p入栈,(状态栈)false入栈,表示还没进行第二次访问。然后不断遍历左孩子。

③如果状态栈首元素为true(此时为第三次访问树节点),获得栈首树节点然后输出数据,出栈。

    否则状态栈首元素为false(此时为第二次访问树节点),将状态改成false,然后访问其右孩子。

④如果到达栈底(NULL)就跳出无限循环。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值