二叉树的非递归遍历

测试环境:VS 2010

上篇文章我们实现了二叉树:http://blog.csdn.net/snow_5288/article/details/53672367


        现在,简单说下二叉树的非递归遍历(其他函数也可按照相似的方式用非递归实现)。以前我们知道,凡是可用递归实现的代码我们都可用栈来模拟它,今天就来简单模拟实现一下二叉树的非递归遍历,上述链接中的其他函数也可通过栈来进行模拟,因为遍历应用比较广泛,所以我只对它进行改写,其他函数有兴趣的可自己仿照实现,如若有问题随时欢迎来打扰我吐舌头偷笑大笑


1、先序遍历

基本思想:

1>首先定义一个栈,每遇到一个节点,就对其数据进行访问;然后将其入栈,将当前节点的左孩子赋给它,循环此过程,直到最左节点被访问并被压入栈中。

2>出循环后用临时变量保存栈顶节点,然后对栈顶节点进行出栈操作,到此说明当前节点以及其左子树已被访问过了。

3>将临时变量的右孩子赋给当前节点,用子问题的方式去访问其右子树。

void preorderR(Node* root)//先序遍历打印树的各个节点
	{
		Node* cur = root;
		stack<Node*> s;
		while (!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			while(cur)//先序遍历,遇到树根节点直接访问数据并将其压栈
			{
				cout<<cur->_value<<" ";
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取出栈顶元素,到此说明此节点以及其左子树已经访问过了
			s.pop();

			cur = top->_rchild;//以子问题的方式去访问右子树
		}
		cout<<endl;
	}


2、中序遍历

基本思想:

1>首先定义一个栈,每遇到一个节点,就将其入栈,将当前节点的左孩子赋给它,循环此过程,直到最左节点将其压入栈中。

2>出循环后用临时变量保存栈顶节点,访问栈顶节点的数据,然后对栈顶节点进行出栈操作,到此说明当前节点的左子树以及当前节点已被访问过了。

3>将临时变量的右孩子赋给当前节点,用子问题的方式去访问其右子树。

	void inorderR(Node* root)//中序遍历打印树的各个节点
	{
		Node* cur = root;
		stack<Node*> s;
		while(!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			while(cur)//中序遍历,遇到树根节点直接将其压栈
			{
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取出栈顶元素,到此说明此节点的左子树已经访问过了
			cout<<top->_value<<" ";//访问栈顶元素(即根节点)
			s.pop();

			cur = top->_rchild;//以子问题的方式去访问右子树
		}
		cout<<endl;
	}


3、后序遍历

1>首先定义一个栈和一个记录上一个被访问节点的变量,每遇到一个节点,就对其数据进行访问;然后将其入栈,将当前节点的左孩子赋给它,循环此过程,直到最左节点被访问并被压入栈中。

2>出循环后用临时变量保存栈顶元素,只有当前节点的右子树为空或者其右子树已经访问过时,才能对当前节点进行访问,同时将栈顶元素出栈

3>将临时变量的右孩子赋给当前节点,用子问题的方式去访问其右子树。


void postorderR(Node* root)//后序遍历打印树的各个节点
	{
		Node* cur = root;
		Node* prev = NULL;//上一个访问过的数据
		stack<Node*> s;
		while(!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			//后序遍历,遇到树根节点直接将其压栈
			while(cur)
			{
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取栈顶元素,但不一定能访问
			
			//当节点右子树为空或已经访问过时对其直接进行访问
			if (top->_rchild==NULL || top->_rchild==prev)
			{
				cout<<top->_value<<" ";
				prev = top;//将prev更新为已经访问的节点
				s.pop();
			}
			else//以子问题的方式去访问右子树
			{
				cur = top->_rchild;
			}
	   }
		cout<<endl;
	}

完整的代码及测试:

#include <iostream>
#include <cassert>
#include <queue>
#include <stack>
using namespace std;

template <class T>
struct TreeNode
{
	TreeNode(const T& value = T())
		:_value(value)
		,_lchild(0)
		,_rchild(0)
	{}
	T _value;//节点的值
	TreeNode<T>* _lchild;//左孩子
	TreeNode<T>* _rchild;//右孩子
};

template <class T>
class BinaryTree
{
public:
	typedef TreeNode<T> Node;
	BinaryTree()//无参构造函数
		:_root(NULL)
	{}
	BinaryTree(const T* a,size_t size,const T& invalid)//构造函数
	{
		assert(a);
		size_t index = 0;
		_root = CreatTree(a,size,invalid,index);
	}
	BinaryTree(const BinaryTree<T>& b)//拷贝构造
	{
		_root = Copy(b._root);
	}
	//现代写法的赋值运算符重载1
	BinaryTree& operator=(const BinaryTree<T>& b)
	{
		if (this != &b)
		{
			Node* tmp = Copy(b._root);
			Destroy(_root) ;
			_root = tmp;
			//swap(_root,tmp);
		}
		return *this;
	}
	现代写法的赋值运算符重载2
	//BinaryTree& operator=(BinaryTree<T> b)
	//{
	//	swap(b._root,_root);
	//	return *this;
	//}
	~BinaryTree()//析构
	{
		if (NULL != _root)
		{
			Destroy(_root);
			_root = NULL;
		}
	}
	void PreOrder()//先序遍历打印树的各个节点
	{
		cout<<"先序遍历:";
		preorderR(_root);
		cout<<endl;
	}
	void InOrder()//中序遍历打印树的各个节点
	{
		cout<<"中序遍历:";
		inorderR(_root);
		cout<<endl;
	}
	void PostOrder()//后序遍历打印树的各个节点
	{
		cout<<"后序遍历:";
		postorderR(_root);
		cout<<endl;
	}
	void LevelOrder()//层序遍历打印树的各个节点
	{
		cout<<"层序遍历:";
		levelorder(_root);
		cout<<endl;
	}
	size_t Size()//求树中的节点个数
	{
		cout<<"size:";
		return size(_root);
	}
	size_t Depth()//求树的深度
	{
		cout<<"depth:";
		return depth(_root);
	}
	size_t GetLeafSize()
	{
		cout<<"leaf_size:";
		return getleafsize(_root);
	}
	size_t GetKLevelSize(size_t k)//树中第k层的节点个数
	{
		cout<<k<<"_level_size:";
		return getklevelsize(_root,k);
	}
protected:
	//按照先序遍历递归建树
	Node* CreatTree(const T* a,size_t size,const T& invalid,size_t& index)//注意index的传值方式
	{
		assert(a);
		Node* root = NULL;
		if (a[index] != invalid && index < size)//按先序遍历建树
		{
			root = new Node(a[index]);
			root->_lchild = CreatTree(a,size,invalid,++index);
			root->_rchild = CreatTree(a,size,invalid,++index);
		}
		return root;
	}
	//拷贝对象
	Node* Copy(Node* root)
	{
		Node* tmp = NULL;

		if(root)
		{
			tmp = new Node(root->_value);
			tmp->_lchild = Copy(root->_lchild);
			tmp->_rchild = Copy(root->_rchild);
		}
		return tmp;
	}
	//释放空间
	void Destroy(Node*& root)
	{
		if(root)//用后序遍历方式释放空间
		{
			Destroy(root->_rchild);
			Destroy(root->_lchild);
			delete root;
			root = NULL;
		}
	}
	void preorderR(Node* root)//先序遍历打印树的各个节点
	{
		Node* cur = root;
		stack<Node*> s;
		while (!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			while(cur)//先序遍历,遇到树根节点直接访问数据并将其压栈
			{
				cout<<cur->_value<<" ";
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取出栈顶元素,到此说明此节点以及其左子树已经访问过了
			s.pop();

			cur = top->_rchild;//以子问题的方式去访问右子树
		}
		cout<<endl;
	}
	void inorderR(Node* root)//中序遍历打印树的各个节点
	{
		Node* cur = root;
		stack<Node*> s;
		while(!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			while(cur)//中序遍历,遇到树根节点直接将其压栈
			{
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取出栈顶元素,到此说明此节点的左子树已经访问过了
			cout<<top->_value<<" ";//访问栈顶元素(即根节点)
			s.pop();

			cur = top->_rchild;//以子问题的方式去访问右子树
		}
		cout<<endl;
	}
	void postorderR(Node* root)//后序遍历打印树的各个节点
	{
		Node* cur = root;
		Node* prev = NULL;//上一个访问过的数据
		stack<Node*> s;
		while(!s.empty() || cur)//只要当前节点和栈不同时为空,就说明树没遍历完
		{
			//后序遍历,遇到树根节点直接将其压栈
			while(cur)
			{
				s.push(cur);
				cur = cur->_lchild;
			}

			Node* top = s.top();//取栈顶元素,但不一定能访问
			
			//当节点右子树为空或已经访问过时对其直接进行访问
			if (top->_rchild==NULL || top->_rchild==prev)
			{
				cout<<top->_value<<" ";
				prev = top;//将prev更新为已经访问的节点
				s.pop();
			}
			else//以子问题的方式去访问右子树
			{
				cur = top->_rchild;
			}
	   }
		cout<<endl;
	}
	
	void levelorder(Node* root)//层序遍历打印树的各个节点
	{
		queue<Node*> q;
		if (root)
		{
			q.push(root);//将根节点插进队列
		}
		while(!q.empty())
		{
			Node* front = q.front();
			q.pop();
			cout<<front->_value<<" ";
			if (front->_lchild)
			{
				q.push(front->_lchild);
			}
			if (front->_rchild)
			{
				q.push(front->_rchild);
			}
		}
	}
	size_t size(Node* root)//求树中的节点个数
	{
		size_t count = 0;
		if (NULL == root)
		{
			count = 0;
		}
		else
		{
			//当前节点 = 左子树节点 + 右子树节点 + 1
			count = size(root->_lchild) + size(root->_rchild)+ 1;
		}
		return count;
	}
	size_t depth(Node* root)//求树的深度
	{
		if (NULL == root)
		{
			return 0;
		}
		else
		{
			return depth(root->_lchild)>depth(root->_rchild)?
				(depth(root->_lchild)+1):(depth(root->_rchild)+1);
		}
	}
	size_t getleafsize(Node* root)//求叶节点的个数
	{
		if (NULL == root)//空树
		{
			return 0;
		}
		if (NULL == root->_lchild && NULL == root->_rchild)//左叶节点右节点均为空,即
		{
			return 1;
		}
		else//左子树的叶节点+右子树的叶节点
		{
			return getleafsize(root->_lchild)+getleafsize(root->_rchild);
		}
	}
	size_t getklevelsize(Node* root,size_t k)//树中第k层的节点个数
	{
		assert(k>0);

		size_t count = 0;
		if (NULL == root)
		{
			return 0;
		}
		if (k == 1)
		{
			count++;
		}
		else
		{
			count =  getklevelsize(root->_lchild,k-1)
				+ getklevelsize(root->_rchild,k-1);
		}
		return count;
	}
protected:
	Node* _root;//根节点
};

void TestBinaryTree()
{
	int arr[] = {1, 2, 3, '#', '#', 4, '#' , '#', 5, 6,'#','#','#'};
	size_t size = sizeof(arr)/sizeof(arr[0]);
	BinaryTree<int> bt(arr,size,'#');
	BinaryTree<int> b1(bt);
	BinaryTree<int> b2;
	b2 = bt;
	b2.PreOrder();
	b2.InOrder();
	b2.PostOrder();
	b2.LevelOrder();
	cout<<b2.Size()<<endl;
	cout<<b2.Depth()<<endl;
	cout<<b2.GetLeafSize()<<endl;
	cout<<b2.GetKLevelSize(1)<<endl;
	cout<<b2.GetKLevelSize(2)<<endl;
	cout<<b2.GetKLevelSize(3)<<endl;
}

int main()
{
	TestBinaryTree();
	system("pause");
	return 0;
}
测试结果:





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值