数据结构与算法问题 二叉树的建立与遍历(含非递归)

                                                                                                 二叉树的非递归遍历

         二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。

 

一.递归遍历

void preorder(bitree * &root)  //前序遍历
{
	if(root)
	{
		cout<<root->data;
		preorder(root->lchild);
		preorder(root->rchild);
	}
}


void inorder(bitree * & root)  //中序遍历
{
	if(root)
	{
		inorder(root->lchild);
		cout<<root->data;
		inorder(root->rchild);
	}
}


void postorder(bitree * & root) //后序遍历
{
	if(root)
	{
		postorder(root->lchild);
		postorder(root->rchild);
		cout<<root->data;
	}
}


 

 

二.非递归遍历

   运用栈的方法进行遍历。

void prebitree(bitree * &root)  //前序遍历
{
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			s.push(root);
			cout<<root->data;
			root=root->lchild;
		}
		if(!s.empty())
		{
			root=s.top();
			root=root->rchild;
			s.pop();
		}
	}
}


void inbitree(bitree * & root) //中序遍历
{
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			s.push(root);
			root=root->lchild;
		}
		if(!s.empty())
		{
			root=s.top();
			cout<<root->data;
			s.pop();
			root=root->rchild;
		}
	}
}


 

 

      后序遍历比较复杂,后序遍历的非递归实现是三种遍历方式中最难的一种。因为在后序遍历中,要保证左孩子和右孩子都已被访问并且左孩子在右孩子前访问才能访问根结点,这就为流程的控制带来了难题。下面介绍两种思路。

      思路:对于任一结点root,将其入栈,然后沿其左子树一直往下搜索,直到搜索到没有左孩子的结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,因此其右孩子还为被访问。所以接下来按照相同的规则对其右子树进行相同的处理,当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。这样就保证了正确的访问顺序。可以看出,在这个过程中,每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。当标志位为1时,不访问,当为2时,进行访问。

 

void postbitree(bitree * & root) //后序遍历
{
	bitree *temp=new bitree;
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			root->flage=1;
			s.push(root);
			root=root->lchild;
		}
		if(!s.empty())
		{
			temp=s.top();
			s.pop();
			if(temp->flage==1)
			{
				temp->flage++;
				s.push(temp);
				root=temp->rchild;
			}
			else
			{
				cout<<temp->data;
				root=NULL;
			}

			
		}


	}
}


 

全部遍历的代码:注意当使用非递归遍历时,root的值最后为NULL,所以需要在遍历中添加P,以防改变root.

 

#include <iostream>
#include <stack>
using namespace std;
typedef struct bitree
{ 
	char data;
	bitree * lchild;
	bitree * rchild;
	int flage;

}bitree;

void create(bitree * &root)
{
	root=new bitree;
	cin>>root->data;
	if(root->data=='.') root=NULL;
	if(root)
	{
		
		create(root->lchild);
		create(root->rchild);
	}

}

void preorder(bitree * &root)
{
	if(root)
	{
		cout<<root->data;
		preorder(root->lchild);
		preorder(root->rchild);
	}
}

void prebitree(bitree * &root)  //前序遍历
{
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			s.push(root);
			cout<<root->data;
			root=root->lchild;
		}
		if(!s.empty())
		{
			root=s.top();
			root=root->rchild;
			s.pop();
		}
	}
}

void inorder(bitree * & root)  //中序遍历
{
	if(root)
	{
		inorder(root->lchild);
		cout<<root->data;
		inorder(root->rchild);
	}
}

void inbitree(bitree * & root) //中序遍历
{
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			s.push(root);
			root=root->lchild;
		}
		if(!s.empty())
		{
			root=s.top();
			cout<<root->data;
			s.pop();
			root=root->rchild;
		}
	}
}

void postorder(bitree * & root)
{
	if(root)
	{
		postorder(root->lchild);
		postorder(root->rchild);
		cout<<root->data;
	}
}

void postbitree(bitree * & root) //后序遍历
{
	bitree *temp=new bitree;
	stack<bitree *> s;
	while(root!=NULL||!s.empty())
	{
		while(root!=NULL)
		{
			root->flage=1;
			s.push(root);
			root=root->lchild;
		}
		if(!s.empty())
		{
			temp=s.top();
			s.pop();
			if(temp->flage==1)
			{
				temp->flage++;
				s.push(temp);
				root=temp->rchild;
			}
			else
			{
				cout<<temp->data;
				root=NULL;
			}

			
		}


	}
}


int main()
{
	bitree * root;
	create(root);
	preorder(root);
	cout<<endl;
	prebitree(root);
	cout<<endl;
	inorder(root);
	cout<<endl;
	inbitree(root);
	cout<<endl;
	postorder(root);
	postbitree(root);
	return 0;
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值