二叉树的非递归遍历

本篇博客的主要内容是:

1.二叉树前序遍历(非递归)

2.二叉树中序遍历(非递归)

3.二叉树后序遍历(非递归)

首先给出二叉树形象图


一.

二叉树的前序遍历

方法1:

算法:①将根和左子树每个结点都用循环压栈进去

            ②当循环跳出来以后意味着左子树处理完了,这个时候弹出栈顶元素,判断此元素是否有右子数,如果有进入右子书,然后把右子数当成一个新的结点继续从头开始遍历其左子树,如果次元素的右子树为空,则将当前的cur处理为NULL,因为不处理的话,下一次重新循环的时候又会把栈顶弹出来的那个元素压栈进去造成死循环,这里就需要我们自己标记一下了。

算法代码:

void _PreOrder(_PNode _pRoot)//前序遍历
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur||!s.empty())
		{
			//压左子树
			while (cur)//将根节点和左子树全部压栈
			{
				cout << cur->_data << " ";//打印根节点
				s.push(cur);
				cur = cur->lchild;
			}
			cur = s.top();//弹出栈顶的元素
			s.pop();
			//进入又子树
			if (cur->rchild)
			{
				cur = cur->rchild;
			}
			else//右子树为空的话标记cur为NULL
			{
				cur = NULL;
			}
		}
	}
方法2:

  先将右子树压栈,然后再将左子树压栈,然后弹出栈顶元素以此类推。注意弹出元素的前提是栈不为空
算法代码:

void _PreOrdertwo(_PNode _pRoot)//函数的实现//前序遍历
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur || !s.empty())
		{
				cout << cur->_data << " ";
				if (cur->rchild)
				{
					s.push(cur->rchild);
				}
				if (cur->lchild)
				{
					s.push(cur->lchild);
				}
				if (!s.empty())
				{
					cur = s.top();
					s.pop();
				}
				else
				{
					cur = NULL;
				}
		}
	}
二.

二叉树的中序遍历,这个和二叉树的前序遍历的第一种算法一模一样,只是在打印结点元素的时候是在弹出栈顶元素之后才打印。

算法代码:

void _InOrder(_PNode pRoot)//中序遍历方法1
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur || !s.empty())
		{
			//压左子树
			while (cur)//将根节点和左子树全部压栈
			{
				s.push(cur);
				cur = cur->lchild;
			}
			cur = s.top();//弹出栈顶的元素
			cout << cur->_data << " ";
			s.pop();
			//进入右子数
			if (cur->rchild)
			{
				cur = cur->rchild;
			}
			else
			{
				cur = NULL;
			}
		}
	}

二叉树的后续遍历

算法:这个算法和前序遍历的方法1比较类似。

        ①将根和左子树全部压栈

       ②当左子树压栈完成以后开始处理右子数,在这里需要注意

      当右子树为空的时候将当前的结点用另外的变量标记下来,不然的话下次的循环开始又会将其压栈进去造成死循环,还有就是需要注意当弹出元素的前提是栈不为空,如果为空证明遍历结束了,直接返回。如果不好理解的话,单步调试跟着代码走一遍就清除了。
算法代码:

void _PostOrder(_PNode Proot)
	{
		stack<_PNode> s;
		_PNode cur = Proot;
		_PNode pre = NULL;
		while (!s.empty() ||cur )
		{
			while (cur&&cur!=pre)
			{
				s.push(cur);
				cur = cur->lchild;
			}
			if (s.empty())
				return;
			cur = s.top();
			if (cur->rchild != NULL&&cur->rchild!=pre)//走到右边的结点中
			{
				cur = cur->rchild;
			}
			else
			{
				cout << cur->_data << " ";
				s.pop();
				pre = cur;//标记这个Cur
			}
		}
	}

注意:

在遍历的时候区分清除什么时候该打印很重要!

下面给出完整的测试代码

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
using namespace std;

template<class T>
struct BinTreeNode
{
	T _data;
	BinTreeNode<T>* lchild;
	BinTreeNode<T>* rchild;
	BinTreeNode(const T& data)
		:_data(data)
		, lchild(NULL)
		, rchild(NULL)
	{}
};
template<class T>
class BinTree
{
public:
	typedef BinTreeNode<T> _Node;
	typedef BinTreeNode<T>* _PNode;
public:
	BinTree(const T*array, size_t size, const T& invalue)//构造函数创建二叉树
	{
		size_t index = 0;
		_CreatBinTree(&_pRoot, array, size, index, invalue);
	}
	void PreOrder()//前序非递归遍历方法1.
	{
		_PreOrder(_pRoot);//函数的实现
		cout << endl;
	}
	void PreOrdertwo()//前序遍历非递归方法的第二种
	{
		_PreOrdertwo(_pRoot);//函数的实现
		cout << endl;
	}
	void InOrder()//中序遍历方法1
	{
		_InOrder(_pRoot);
		cout << endl;
	}
	void PostOrder()//后续遍历
	{
		_PostOrder(_pRoot);
		cout << endl;
	}
private:
	void _CreatBinTree(_PNode *pRoot, const T* array, size_t size, size_t& index, const  T& invalue)
	{
		if (array[index] == invalue || index >= size)
		{
			return;
		}
		*pRoot = new _Node(array[index]);//创建根结点
		_CreatBinTree(&((*pRoot)->lchild), array, size, ++index, invalue);
		_CreatBinTree(&((*pRoot)->rchild), array, size, ++index, invalue);
	}
	void _PreOrder(_PNode _pRoot)//前序遍历方法1
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur||!s.empty())
		{
			//压左子树
			while (cur)//将根节点和左子树全部压栈
			{
				cout << cur->_data << " ";
				s.push(cur);
				cur = cur->lchild;
			}
			cur = s.top();//弹出栈顶的元素
			s.pop();
			//进入又子树
			if (cur->rchild)
			{
				cur = cur->rchild;
			}
			else//右子树为空的话标记cur为NULL
			{
				cur = NULL;
			}
		}
	}
	void _PreOrdertwo(_PNode _pRoot)//函数的实现//前序遍历方法2
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur || !s.empty())
		{
				cout << cur->_data << " ";
				if (cur->rchild)
				{
					s.push(cur->rchild);
				}
				if (cur->lchild)
				{
					s.push(cur->lchild);
				}
				if (!s.empty())
				{
					cur = s.top();
					s.pop();
				}
				else
				{
					cur = NULL;
				}
		}
	}
	void _InOrder(_PNode pRoot)//中序遍历
	{
		stack<_PNode> s;
		_PNode cur = _pRoot;
		while (cur || !s.empty())
		{
			//压左子树
			while (cur)//将根节点和左子树全部压栈
			{
				s.push(cur);
				cur = cur->lchild;
			}
			cur = s.top();//弹出栈顶的元素
			cout << cur->_data << " ";
			s.pop();
			//进入右子数
			if (cur->rchild)
			{
				cur = cur->rchild;
			}
			else
			{
				cur = NULL;
			}
		}
	}
	void _PostOrder(_PNode Proot)//后续遍历
	{
		stack<_PNode> s;
		_PNode cur = Proot;
		_PNode pre = NULL;
		while (!s.empty() ||cur )
		{
			while (cur&&cur!=pre)
			{
				s.push(cur);
				cur = cur->lchild;
			}
			if (s.empty())
				return;
			cur = s.top();
			if (cur->rchild != NULL&&cur->rchild!=pre)//走到右边的结点中
			{
				cur = cur->rchild;
			}
			else
			{
				cout << cur->_data << " ";
				s.pop();
				pre = cur;//标记这个Cur
			}
		}
	}
private:
	_PNode _pRoot;
};
int main()
{
	const char *arr = "ABD##E##CF###";
	BinTree<char> BT(arr, strlen(arr), '#');
	cout << "前序遍历方法1:"; BT.PreOrdertwo();
	cout << "前序遍历方法2:"; BT.PreOrder();
	cout << "中序遍历:"; BT.InOrder();
	cout << "后序遍历:"; BT.PostOrder();
	system("pause");
	return 0;
}
测试结果如下:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值