二叉树的非递归前序、中序、后序遍历(两种方式的非递归后序遍历)

1、先序的非递归

思想:先将根节点放入栈中,先入右节点,再入左节点。根据栈的原理,在访问时是左到右的。

开始时,我将push(index)这个操作放在循环里面,这是一条无限循环的不归路啊

 

template<class T>//非递归先序遍历,使用的是栈
void BST<T>::iterativePreorder()
{//思路:将节点放入栈中,访问之后,先放入右节点,再放入左节点。
	BSTNode<T>*index=root;
	Stack<BSTNode<T>*>preorderStack;
	preorderStack.push(index);//当前节点入栈
	while(index&&!preorderStack.isEmpty())
	{
		index=preorderStack.pop();
		visit(index);//访问此节点
		if (index->right)
		{
			preorderStack.push(index->right);//右节点入栈,如此出栈就是先序遍历
		}
		if (index->left)
		{
			preorderStack.push(index->left);//左节点入栈
		}
	}
}


 

2、中序遍历

首先找到最左边的节点。

中序遍历思维不要定势,采用两重循环,在里面对栈中元素进行操作。

其实在遍历中关键的是何时入栈,出栈,以及访问节点的时机

template<class T>//非递归中序遍历算法
void BST<T>::iterativeInorder()
{   
	//思路:使用一个栈来实现。首先遍历一个节点的左子树。退出一个,将指针重新的赋值
	//刚开始打算使用一个栈,但是并没有增加第二个while,在访问了一个没有右节点的叶子节点后直接的退出
	//重新的赋值于index,有没有右子树都给予包含
	Stack<BSTNode<T>*>inorderStack;
	BSTNode<T>* p=NULL;
	BSTNode<T>* index=root;
	while(index!=NULL)//可能会出现栈中元素 已经为空,而此时元素并没有访问结束
	{
		while(index!=NULL)
		{
			inorderStack.push(index);
			index=index->left;
		}
		while(!inorderStack.isEmpty())//当栈中元素多于一个时,逐个访问栈中元素,
		{
			p=inorderStack.pop();
			visit(p);//访问栈顶元素
			if (p->right)//访问该元素的右子树
			{
				//p=p->right;
				index=p->right;//若节点没有右子树,index为空,返回继续访问栈中下一个元素。
				break;
				//若有右子树,则置index为这个右子树,那么继续从右子树开始访问节点
			}
			//index=p; //开始采取是的是将p的值赋给index,后面发现若是已经到达最后一个节点,会无线的循环。因为index永远不会为空
		}
	}
}


 

3、后序遍历

两种方法,一个是对每个节点增添一个标志的bool值,另外一种是采用两个栈。后序遍历中若采用与前面一样的方法,我们会发现。入栈之后,查看有没有右子树,找到之后index指向这个右子树。访问这个右子树后,出栈又发现这个节点有右子树,于是陷入死循环中。这是我一开始编程犯的错误。于是我想是不是要加一个标志位,但是在程序中有必要为一个后序遍历加一个内存???我不甘,于是我继续的探讨,在一篇文章中发现后序与先序中存在的某些关系,于是发现从左到右的后序与从右到左的先序的逆序是一样的

template<class T>//非递归后序遍历算法
void BST<T>::iterativePostorder2()//利用访问标志
{
	BSTNode<T>*index=root;
	Stack<BSTNode<T>*>postStack;
	while(index&&index->bVisit==false)//若是没有已经访问这一条件,那么整棵树无限的访问
	{
		while(index)
		{
			postStack.push(index);
			index=index->left;//寻找到最左边的节点
		}
		while(!postStack.isEmpty())
		{
			index=postStack.pop();//若是没有节点直接访问,若有,那么还必须把它放入栈,因为之后还会访问
			if (index->right&&(index->right->bVisit==false))//若没有已经访问这个条件,会在一棵树中的右节点与其本身不断的循环
			{
				postStack.push(index);//重新的将刚刚pop的节点放入栈
				index=index->right;//对右子树进行操作
				break;
			}
			else
			{
				index->bVisit=true;//设置访问属性
				visit(index);//访问之
			}
		}
	}
}

template<class T>
void BST<T>::iterativePostorder()//通过两个栈,从左到右后序等于从右到左的先序的逆序。
{
	BSTNode<T> *index=root;
	BSTNode<T> *p=root;
	Stack<BSTNode<T>*>postStack;
	Stack<BSTNode<T>*>postStackReverse;
	postStack.push(index);
	while(index&&!postStack.isEmpty())
	{
		
		index=postStack.pop();
		postStackReverse.push(index);
		if (index->left)//先入左,等于从右到左进行访问
		{
			postStack.push(index->left);
		}
		if (index->right)
		{
			postStack.push(index->right);
		}
	}
	while(!postStackReverse.isEmpty())
	{
		index=postStackReverse.pop();
		visit(index);
	}
}


 

void test()
{
	int testArray[]={15,5,16,3,12,20,4,10,13,18,23,6,7};
	BST<int> bstTree;
	cout<<"原来数组内容为"<<endl;
	for (int nIndex=0;nIndex<13;nIndex++)
	{
		cout<<testArray[nIndex]<<"  ";
		bstTree.insert(testArray[nIndex]);
	}
	/*bstTree->preorder(bstTree->root);
	bstTree->inorder(bstTree->root);
	bstTree->postorder(bstTree->root);*/

	cout<<endl<<"先序的非递归遍历算法结果"<<endl;
	bstTree.iterativePreorder();
	cout<<endl<<"中序的非递归遍历算法结果"<<endl;
	bstTree.iterativeInorder();
	cout<<endl<<"后序的采用已访问标志的非递归遍历算法结果"<<endl;
	bstTree.iterativePostorder();
	cout<<endl<<"后序的采用两个栈的非递归遍历算法结果"<<endl;
	bstTree.iterativePostorder2();
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值