【二叉树的遍历】前中后序、层序遍历(递归与非递归版本)

【0】遍历法则

我们来简单了解一下二叉树的前中后序和层序的遍历法则

层序遍历

层序遍历是最简单的,顾名思义就是一层一层从左往右一个一个打印,不难理解。
在这里插入图片描述

前序遍历

在这里插入图片描述
例:
在这里插入图片描述

输出结果:ABDEGCF

中序遍历

在这里插入图片描述
例:
在这里插入图片描述
输出结果:DBGEACF

后序遍历

在这里插入图片描述
例:
在这里插入图片描述
输出结果:DGEBFCA

【1】非递归前序遍历

//非递归实现前序遍历需要通过辅助栈存父结点来完成所有的操作
//从根节点压栈,然后接下来进行一个大循环
//只要栈里边还有元素,就将栈顶元素输出并且出栈
//将栈顶元素的右孩子结点和左孩子结点依次压栈
//(因为出栈和入栈的顺序是相反的,所以先压右孩子,再压左孩子)
//直到栈空为止

	void NonPre_Post()
	{
		cout << "非递归实现前序遍历:";
		if (_root == nullptr)
		{
			return;
		}
		stack<BSTNode*>s;
		s.push(_root);
		while(!s.empty())
		{
			BSTNode*top = s.top();
			s.pop();
			cout << top->_data << " ";
			if (top->_right != nullptr)
			{
				s.push(top->_right);
			}
			if (top->_left != nullptr)
			{
				s.push(top->_left);
			}
		}
		cout << endl;
	}
递归版本前序遍历
	//递归实现树的前序遍历
	//首先访问根节点,输出根节点的值,此后需要判断递归遍历的每个根节点是否存在
	//然后再按照如上方法递归遍历根节点的左子树
	//再递归遍历根节点的右子树
	void Pre_out()
	{
		cout << "递归实现前序遍历:";
		Pre_out(_root);
		cout << endl;
	}
	
	void Pre_out(BSTNode *node)	
	{
		if (node != nullptr)
		{
			cout << node->_data << " ";
			Pre_out(node->_left);
			Pre_out(node->_right);
		}
	}

【2】非递归中序遍历

需要一个辅助栈,从根节点开始,一直向左子树遍历
将结点压入栈,直到结点为空,然后打印该结点并且出栈该结点
这时将栈顶结点的右子树按照如上方法继续进行。

//非递归实现中序遍历
	void NonMid_Post()
	{
		cout << "非递归实现中序遍历:";
		if (_root == nullptr)
		{
			return;
		}
		stack<BSTNode*>s;
		BSTNode*cur = _root;
		while (!s.empty() || cur != nullptr)
		{
			if (cur != nullptr)
			{
				s.push(cur);
				cur = cur->_left;
			}
			else
			{
				BSTNode*top = s.top();
				s.pop();
				cout << top->_data << " ";
				cur = top->_right;
			}
		}
		cout << endl;
	}
递归版本中序遍历
//递归实现树的中序遍历
//从根结点开始,先访问结点的左孩子,再输出该结点的值,再访问结点的右孩子
//按照上述方式进行递归

void Mid_out()
	{
		cout << "递归实现中序遍历:";
		Mid_out(_root);
		cout << endl;
	}
	
void Mid_out(BSTNode *node)	
{
	if (node != nullptr)
	{
		Mid_out(node->_left);
		cout << node->_data << " ";
		Mid_out(node->_right);
	}
}

【3】非递归后序遍历

非递归的后序遍历需要两个栈进行辅助操作
用一个栈存放父结点,一个栈用于存放结果
注意压栈顺序,本来我们应该先压右孩子,再压左孩子。但是我们使用另一个结果栈 来存储结果集,辅助栈中的元素最终是出栈并压入结果栈的,因此,我们程序中 应该先压入左孩子,再压入右孩子。 然后每次循环将栈顶元素出栈并压入结果栈中。 最后,结果栈中所存储的就是我们所需的后序遍历结果集。最后打印出结果栈。

void NonLast_Post()
	{
		cout << "非递归实现后序遍历:";
		if (_root == nullptr)
		{
			return;
		}
		stack<BSTNode*>sa;
		stack<BSTNode*>sb;
		sa.push(_root);
		while (!sa.empty())
		{
			BSTNode* top = sa.top();
			sa.pop();
			sb.push(top);
			if (top->_left != nullptr)
			{
				sa.push(top->_left);
			}
			if (top->_right != nullptr)
			{
				sa.push(top->_right);
			}
		}
		while (!sb.empty())
		{
			cout << sb.top()->_data << " ";
			sb.pop();
		}
		cout << endl;
	}
递归版本后序遍历
//递归实现树的后序遍历
//从根节点开始,先遍历左孩子,再遍历右孩子
//再打印该结点的值
//按照上述方式一直递归
void Last_out()
	{
		cout << "递归实现后序遍历:";
		Last_out(_root);
		cout << endl;
	}
void Last_out(BSTNode *node)	
	{
		if (node != nullptr)
		{
			Last_out(node->_left);
			Last_out(node->_right);
			cout << node->_data << " ";
		}
	}

【4】非递归层序遍历

//非递归层序遍历需要借助一个队列进行操作
//原因是层序遍历是一个广度优先的遍历操作,需要从左至右,从上至下每一层逐个打印
//首先把根结点入队
//然后进行一个大循环,判断队列是否为空
//只要队列不为空,则说明上一层的元素还没有打印完
//将队头出队,打印队头元素,将队头的左孩子和右孩子依次从队尾入队
//直到队内空,则说明遍历完成。
void NonLeavlshow()
	{
		cout << "非递归实现层序遍历:";
		if (_root == nullptr)
		{
			return;
		}
		queue<BSTNode*>myqueue;
		myqueue.push(_root);
		while (!myqueue.empty())
		{
			if (myqueue.front()->_left)
			{
				myqueue.push(myqueue.front()->_left);
			}
			if (myqueue.front()->_right)
			{
				myqueue.push(myqueue.front()->_right);
			}
			cout << myqueue.front()->_data << " ";
			myqueue.pop();
		}
		cout << endl;
	}
递归版本层序遍历
//递归实现层序遍历
//由于层序遍历是一种广度优先的遍历,所以我们需要通过层数控制整个函数的运行
//每轮循环传入要输出的层数
//然后当层数不等于0时,向下递归,每次递归层数减一
//当层数等于0的时候,则说明已经到达了要输出的那一层,递归的结束条件就满足了,直接输出值即可
	void leavlOrder()
	{
		cout << "递归实现层序遍历:";
		int l = leavl(_root);
		for(int i = 0; i < l; ++i)
		{
			leavlOrder(_root, i);
		}
		cout << endl;
	}

	void leavlOrder(BSTNode *node, int l)
	{
		if (node != nullptr)
		{
			if(l==0)
			{ 
				cout << node->_data << " ";
				return;
			}
			leavlOrder(node->_left, l - 1);
			leavlOrder(node->_right, l - 1);
		}
	}

【5】测试代码

int main()
{
	//				40

	//		20				65
	//	10		25		45		70
	//								99
	//建树
	BSTree<int>bst;
	bst.noninsert(40);
	bst.noninsert(20);
	bst.noninsert(65);
	bst.noninsert(25);
	bst.noninsert(45);
	bst.noninsert(70);
	bst.noninsert(10);
	bst.noninsert(99);
	
	//前序
	bst.Pre_out();
	bst.NonPre_Post();
	cout << endl;
	
	//中序
	bst.Mid_out();
	bst.NonMid_Post();
	cout << endl;
	
	//后序
	bst.Last_out();
	bst.NonLast_Post();
	cout << endl;
	
	//层序
	bst.leavlOrder();
	bst.NonLevelOrder();
	cout << endl;

	return 0;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值