二叉树的基本操作以及相关问题的求解—C++实现

二叉树

二叉树是重要的数据结构,在学习中以及考试、面试中不可避免的考点,现在我就把有关二叉树的操作用C++总结 一下,可能有些同学使用的是C语言,但是无论C语言还是c++,对于二叉树的操作方法都是一样的,之后,我也会抽空给出C语言的实现。

本次实现是在vs2008的一个集成开发环境,为了增强代码的复用性,此次编写使用了模版,关于模版可以参考的我的另外一篇博客:http://blog.csdn.net/dy_1024/article/details/78643644,如果大家在使用的时候,不实用模版,只需把代码中的模版类型T,换成你需要的类型即可。

首先我们用结构体给出二叉树结点的结构:

template//如果大家不使用模版的话,把这行代码去掉,将结构体中的T该成你需要的类型即可
struct BinTreeNode{
	BinTreeNode(const T& data):_left(NULL),_right(NULL),_data(data){}//二叉树结点的构造函数,方便之后给出新结点
	BinTreeNode* _right;//右子树
	BinTreeNode* _left;//左子树
	T _data;//数据域
};
因为使用c++,所以我们将二叉树封装成一个二叉树类,进行管理,同样使用模版:

template
class  BinTree
{
	typedef BinTreeNode Node;//将之前的类此重定义,方便以后的使用
	typedef Node* PNode;
public:
	BinTree():_pRoot(NULL){}
	//构造函数里面使用的创建二叉树的函数,
	void _CreatBinTree(PNode& pRoot,const T* array,size_t size,size_t& index,const T& invalid)
	{
		if(index_left,array,size,++index,invalid);
			_CreatBinTree(pRoot->_right,array,size,++index,invalid);
		}
	}
	//构造函数,在给构造函数传参的时候,我们定义:char *array ="ABD###CE##F",这是二叉树前序遍历的结果,"#"代表无效值,也就是空子树
	BinTree(const T* array,size_t size,const T& invalid)
	{
		size_t index = 0;
		_CreatBinTree(_pRoot,array,size,index,invalid);//我们将二叉树的构造封装成函数,这样结构比较明确
	}
	//前序遍历
	void _PreOrder(PNode pRoot)
	{
		if(pRoot)
		{
			cout<_data<<" ";
			_PreOrder(pRoot->_left);
			_PreOrder(pRoot->_right);
		}
	}
	//中序遍历
	void _InOrder(PNode pRoot)
	{
		if(pRoot)
		{
			_InOrder(pRoot->_left);
			cout<_data<<" ";
			_InOrder(pRoot->_right);
		}
	}
	//后续遍历
	void _PostOrder(PNode pRoot)
	{
		if(pRoot)
		{
			_PostOrder(pRoot->_left);
			_PostOrder(pRoot->_right);
			cout<_data<<" ";
		}
	}
	//拷贝构造函数里面需要的拷贝函数
	PNode _CopyBinTree(PNode pRoot)
	{
		PNode pNewNode = NULL;
		if(pRoot)
		{
			pNewNode = new Node(pRoot->_data);
			pNewNode->_left = _CopyBinTree(pRoot->_left);
			pNewNode->_right = _CopyBinTree(pRoot->_right);
		}
		return pNewNode;
	}
	BinTree(const BinTree& bt)//拷贝构造函数
	{
		_pRoot = _CopyBinTree(bt._pRoot);
	}
	//销毁函数
	void _DestoryBinTree(PNode& pRoot)
	{
		if(pRoot)
		{
			_DestoryBinTree(pRoot->_left);
			_DestoryBinTree(pRoot->_right);
		}
		delete pRoot;
		pRoot = NULL;
	}
	//赋值运算符重载
	BinTree& operator=(const BinTree& bt)
	{
		//把原有的树销毁掉,在用拷贝函数,拷贝一个新树
		_DestoryBinTree(_pRoot);
		_pRoot = _CopyBinTree(bt._pRoot);
		return *this;
	}
	//求树的高度
	size_t _Height(PNode pRoot)
	{
		if(NULL == pRoot)
			return 0;
		if(pRoot->_left == NULL && pRoot->_right == NULL)
		{
			return 1;
		}
		size_t left = _Height(pRoot->_left);//将左子树的高度赋值给left
		size_t right = _Height(pRoot->_right);//将右子树的高度赋值给right
		return left>right?(left+1):(right+1);比较左右子树的大小,大的再加上1,就是树的大小
	}
	//求按层遍历的个数,思路:当你要求第3层的时候,如果以第二层为根,那么就是求第二层的结点,依次遍历
	size_t _GetKLevelNodeCount(PNode pRoot,size_t k)
	{
		if(k == 0 || NULL == pRoot)return 0;
		if(k == 1)return 1;
		return _GetKLevelNodeCount(pRoot->_left,k-1)+_GetKLevelNodeCount(pRoot->_right,k-1);
	}
	//按层遍历,我们使用队列结构保存每次收集的结点,运用队列队头出队尾进的特点,输出每一层的结点
	void _LevelOrder(PNode pRoot)
	{
		PNode pCur = NULL;
		queue q;
		q.push(pRoot);
		while (!q.empty())
		{
			pCur = q.front();
			cout<_data<<" ";
			if(pCur->_left)
				q.push(pCur->_left);
			if(pCur->_right)
				q.push(pCur->_right);
			q.pop();
		}
	}
	//判断结点是否在树中
	bool _IsNodeInBinTree(PNode pRoot,PNode pNode)
	{
		if(NULL == pRoot || pNode == NULL)
			return false;
		if(pRoot == pNode)
			return true;
		bool Isflag = _IsNodeInBinTree(pRoot->_left,pNode);
		if(Isflag)
			return true;
		return _IsNodeInBinTree(pRoot->_right,pNode);
	}
	//在树种找到一个结点
	PNode _Find(PNode pRoot,const T& data)
	{
		if(NULL == pRoot)
			return NULL;
		if(pRoot->_data == data)
			return pRoot;
		PNode pCur = NULL;
		if(pCur = _Find(pRoot->_left,data))
			return pCur;
		return _Find(pRoot->_right,data);
	}
	//求树的镜像—递归
	void _Mirror(PNode pRoot)
	{
		swap(pRoot->_left, pRoot->_right);//直接交换左右子树里面的地址,那么他的左右子树就交换成功了
		if(pRoot->_left)
			_Mirror(pRoot->_left);
		if(pRoot->_right)
			_Mirror(pRoot->_right);
	}
	//求树得镜像-非递归
	void _Mirror_nor(PNode pRoot)
	{
		if(NULL == pRoot)
			return;
		queue q;
		q.push(pRoot);
		while (!q.empty())
		{
			PNode pCur = q.front();
			swap(pCur->_left,pCur->_right);
			if(pCur->_left)
				q.push(pCur->_left);
			if(pCur->_right)
				q.push(pCur->_right);
			q.pop();
		}
	}
	//判断一棵二叉树是不是一颗完全二叉树,当我们发现一个结点只有左子树,没有右子树的时候,就要开始判断
//下一个结点有没有子树,如果有就不是,如果没有就继续,和层序遍历一样,使用队列结构
bool _IsCompleteBinTree(PNode pRoot){if(NULL == pRoot)return true;queue q;q.push(pRoot);bool Isflag = false;while (!q.empty()){PNode pCur = q.front();if(Isflag){if(pCur->_left || pCur->_right)return false;}if(pCur->_left && pCur->_right){q.push(pCur->_left);q.push(pCur->_right);}else if(pCur->_left){q.push(pCur->_left);Isflag = true;}else if(pCur->_right){return false;}else {return true;}q.pop();}return false;} //前序遍历—非递归 (利用栈的特点,只能栈顶出入,来遍历二叉树)void _PreOrder_nor(PNode pRoot){if(NULL == pRoot)return ;stack s;s.push(pRoot);while (!s.empty()){PNode pCur = s.top();s.pop();cout<_data<<" ";if(pCur->_right)s.push(pCur->_right);if(pCur->_left)s.push(pCur->_left);}}//接口,(因为是在类里面封装,所以封装接口之后,就可以不用给函数传参,更加简洁)void PreOrder_nor(){cout<<"PreOrder_nor: "<
 
  


限于编者水平,本文文章难免有缺漏之处,欢迎指正

Tip:如需转载,请注明出处











你可能感兴趣的:(c++)