【数据结构】二叉树

      树是数据结构中非常重要的一部分内容,尤其是二叉树。

什么是二叉树?

      树是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。

      二叉树则是每个结点最多有两个子树的树,二叉树的度最多为2,。左侧子树的称为左子树,右侧子树的称为右子树。




二叉树中有着一些非常重要的推论

1. 度为2的结点比度为0的结点少1个;

2. 具有n个结点的完全二叉树的深度k 为log2(n+1)个结点;

3. 若规定根结点的层数为1,则非空二叉树第i层上最多有2^(i-1)个结点;

4. 若规定只有根结点的二叉树深度为1,则深度为k的二叉树最多有2^k-1个结点;

5. 若对于具有n个结点的完全二叉树,从上至下,从左至右排序依次从0开始,那么对于序号i:

   (1)若i>0序号为i的结点的双亲结点序号为(i-1)/2;

   (2)若2*i+1<n,则序号为i的结点左孩子结点序号为2*i+1;若2*i+1>=n,则无左孩子;

   (3)若2*i+1<n,则序号为i的结点右孩子结点序号为2*i+2;若2*i+1>=n,则无右孩子;

二叉树的结构

struct BinTreeNode
{
	BinTreeNode(const T& data)
	: _pLeft(NULL)
	, _pRight(NULL)
	, _data(data)
	{}
	BinTreeNode<T>* _pLeft;
	BinTreeNode<T>* _pRight;
	T _data;
};
二叉树的遍历:二叉树由左子树+根+右子树构成,二叉树的遍历可以分为四种:前序,中序,后序层序遍历四种。

前序遍历:根+左子树+右子树,即:先访问根,在访问左子树,在访问右子树;

中序遍历:左子树+根+右子树,即:先访问左子树,在访问根,在访问右子树;

后序遍历:左子树+右子树+根,即:先访问左子树,在访问右子树,在访问根;

层序遍历:按层的顺序,一层一层的遍历。

void _PreOrder(pNode pRoot)//前序
{
	if (pRoot)
	{
		cout << pRoot->_data << " ";
		_PreOrder(pRoot->_pLeft);
		_PreOrder(pRoot->_pRight);
	}
}
void _InOrder(pNode pRoot)//中序
{
	if (pRoot)
	{
		_InOrder(pRoot->_pLeft);
		cout << pRoot->_data << " ";
		_InOrder(pRoot->_pRight);
	}
}
void _PostOrder(pNode pRoot)//后序
{
	if (pRoot)
	{
		_PostOrder(pRoot->_pLeft);
		_PostOrder(pRoot->_pRight);
		cout << pRoot->_data << " ";
	}
}
void _LevelOrder(pNode pRoot)//层序:层序的实现较为复杂,需要借助到队列,创建队列,将根结点入队,取队头元素
{                            //访问队头元素并出队列,如果左子树不为空,则保存左子树结点,保存右子树结点。
	if (NULL == pRoot)
		return;
	queue<pNode> q;
	q.push(pRoot);
	while (!q.empty())
	{
		pNode pCur = q.front();
		cout << pCur->_data << " ";
		q.pop();

		if (pCur->_pLeft)
			q.push(pCur->_pLeft);
		if (pCur->_pRight)
			q.push(pCur->_pRight);
	}
}
二叉树的创建:我们可以按照前序遍历的思想,先创建根结点,在创建左子树,在创建右子树;在创建的过程中,为了方便创建,我们将‘#’作为无效的标志,当结点无左孩子或右孩子时我们添加一个‘#’。

void _CreateBinTree(pNode& pRoot, const T* arr, size_t size, size_t& index, const T& invalid)
{       ////index必须传引用,否则函数调用完,index变回原来的值
	if (index < size && '#' != arr[index])//先后次序,首先不能越界,再判断是否为有效值,越界时二叉树已创立完成,不需要在判断是否为有效值了
	{
		pRoot = new Node(arr[index]);

		_CreateBinTree(pRoot->_pLeft, arr, size, ++index, invalid);

		_CreateBinTree(pRoot->_pRight, arr, size, ++index, invalid);
	}	
}

下面我们还要计算二叉树的结点的个数,叶子结点的个数,第K层结点的个数,树的高度,查找值为data的结点,查找双亲结点,查找孩子节点,求一个二叉树的镜像以及判断一个树是不是完全二叉树。

template <class T>
class BinTree
{
	typedef BinTreeNode<T>* pNode;
	typedef BinTreeNode<T> Node;
public:
	//////////////////////////////////////构造函数 拷贝构造 析构函数///////////////////////////////////////
	BinTree()
		: _pRoot(NULL)
	{}
	BinTree(const T*arr, size_t size, const T& invalid)//构造函数
	{
		size_t index = 0;
		_CreateBinTree(_pRoot, arr, size, index, invalid);//创建二叉树
	}
	BinTree(const BinTree<T>& bt)
	{
		_pRoot = _CopyBinTree(bt._pRoot);
	}
	BinTree& operator=(const BinTree& bt)//赋值运算符重载
	{
		if (this != &bt)
		{
			_DesrtoryBinTree(_pRoot);//当前树可能不为空,因此先要销毁原树
			_pRoot = _CopyBinTree(bt._pRoot);
		}
		return *this;
	}
	~BinTree()//析构函数
	{
		_DesrtoryBinTree(_pRoot);
	}
	////////////////////////////////////////////////遍历函数/////////////////////////////////////////////////
	void PreOrder()//前序
	{
		_PreOrder(_pRoot);
		cout << endl;
	}
	void PreOrder_N1()
	{
		if (NULL == _pRoot)
			return;
		stack<pNode> s;
		s.push(_pRoot);
		while (!s.empty())
		{
			pNode pTop = s.top();
			cout << pTop->_data << " ";
			s.pop();
			if (pTop->_pRight)
				s.push(pTop->_pRight);
			if (pTop->_pLeft)
				s.push(pTop->_pLeft);
		}
		cout << endl;
	}
	void PreOrder_N2()
	{
		if (NULL == _pRoot)
			return;
		stack<pNode> s;
		s.push(_pRoot);
		while (!s.empty())
		{
			pNode pCur = s.top();
			s.pop();
			while (pCur)
			{
				cout << pCur->_data << " ";
				if (pCur->_pRight)
					s.push(pCur->_pRight);
				pCur = pCur->_pLeft;
			}
		}
		cout << endl;
	}
	void InOrder()//中序
	{
		_InOrder(_pRoot);
		cout << endl;
	}
	void InOrder_N()
	{
		if (NULL == _pRoot)
			return;
		stack<pNode> s;
		pNode pCur = _pRoot;
		while (pCur || !s.empty())
		{
			while (pCur)//找到最左侧的结点
			{
				s.push(pCur);
				pCur = pCur->_pLeft;
			}
			pCur = s.top();
			cout << pCur->_data << " ";
			s.pop();
			pCur = pCur->_pRight;//将右子树也是一个树
		}
		cout << endl;
	}
	void PostOrder()//后序
	{
		_PostOrder(_pRoot);
		cout << endl;
	}
	void PostOrder_N()
	{
		if (NULL == _pRoot)
			return;
		pNode pCur = _pRoot;
		pNode prev = NULL;
		stack<pNode> s;
		while (pCur || !s.empty())
		{
			while (pCur)
			{
				s.push(pCur);
				pCur = pCur->_pLeft;
			}
			pNode pTop = s.top();
			if (pTop->_pRight == NULL || prev == pTop->_pRight)
			{
				cout << pTop->_data << " ";
				prev = pTop;
				s.pop();
			}
			else
				pCur = pTop->_pRight;
		}
		cout << endl;
	}
	void LevelOrder()//层序
	{
		_LevelOrder(_pRoot);
		cout << endl;
	}
	//////////////////////////////////////////结点个数,高度等///////////////////////////////////////////
	size_t Size()//结点个数
	{
		return _Size(_pRoot);
	}
	size_t GetLeafCount()//叶子结点个数
	{
		return _GetLeafCount(_pRoot);
	}
	size_t GetKLevelCount(size_t K)//获取第K层结点的个数 
	{
		return _GetLevelCount(_pRoot, K);
	}
	size_t Height()//树的高度
	{
		return _Height(_pRoot);
	}
	pNode Find(const T& data)//查找值为data的结点
	{
		return _Find(_pRoot, data);
	}
	pNode Parent(pNode PNode)//找双亲结点
	{
		return _Parent(_pRoot, PNode);
	}
	pNode LeftChild(pNode PNode)//找左孩子
	{
		return (NULL == PNode) ? NULL : PNode->_pLeft;
	}
	pNode RightChild(pNode PNode)//找右孩子
	{
		return (NULL == PNode) ? NULL : PNode->_pRight;
	}
	void Mirror()//递归镜像
	{
		_Mirror(_pRoot);
	}
	void Mirror_N()//非递归镜像
	{
		if (NULL == _pRoot)
			return;
		queue<pNode> q;
		q.push(_pRoot);
		while (!q.empty())
		{
			pNode pCur = q.front();
			swap(pCur->_pLeft, pCur->_pRight);
			q.pop();
			if (pCur->_pLeft)
				q.push(pCur->_pLeft);
			if (pCur->_pRight)
				q.push(pCur->_pRight);
		}
	}
	bool IsCompleteBinTree()//判断是否为完全二叉树
	{
		if (NULL == _pRoot)
			return true;
		queue<pNode> q;
		q.push(_pRoot);
		bool flag = false;
		pNode pCur = NULL;
		while (!q.empty())
		{
			pCur = q.front();//分为四种,当左右都不存在,保存下来,当左存在右不存在,将flag改为true,再判断
				//当左不存在右存在,一定不是完全二叉树,当左右都不存在,改为true,继续判断
			if (flag && (pCur->_pLeft || pCur->_pRight))
			{
				return false;//当pCur为不饱和结点的时候,flag为true,此时pCur若左孩子或右孩子都不是完全二叉树
			}
			else
			{	
				if (pCur->_pLeft && pCur->_pRight)
				{
					q.push(pCur->_pLeft);
					q.push(pCur->_pRight);
				}
				else if (pCur->_pLeft)//不饱和结点
				{
					q.push(pCur->_pLeft);
					flag = true;
				}
				else if (pCur->_pRight)
					return false;
				else//不饱和结点
					flag = true;
			}
			q.pop();
		}
		return true;
	}
private:
	void _CreateBinTree(pNode& pRoot, const T* arr, size_t size, size_t& index, const T& invalid)//创建二叉树
	{     //index必须传引用,否则函数调用完,index变回原来的值   不能引用常量
		if (index < size && invalid != arr[index])//先后次序,首先不能越界
		{
			pRoot = new Node(arr[index]);//创建根结点
			_CreateBinTree(pRoot->_pLeft, arr, size, ++index, invalid);//创建左子树
			_CreateBinTree(pRoot->_pRight, arr, size, ++index, invalid);//创建右子树
		}
	}
	pNode _CopyBinTree(pNode pRoot)//拷贝二叉树
	{
		pNode pNewRoot = NULL;
		if (pRoot)
		{
			pNewRoot = new Node(pRoot->_data);//拷贝根节点
			if (pRoot->_pLeft)//左子树不存在就不用拷了
				pNewRoot->_pLeft = _CopyBinTree(pRoot->_pLeft);//拷贝左子树
			if (pRoot->_pRight)
				pNewRoot->_pRight = _CopyBinTree(pRoot->_pRight);//拷贝右子树
		}
		return pNewRoot;
	}
	void _DesrtoryBinTree(pNode pRoot)//销毁二叉树
	{//采用后序遍历的思想,否则,先销毁根节点,左右子树将找不到了
		if (pRoot)
		{
			_DesrtoryBinTree(pRoot->_pLeft);//销毁左子树
			_DesrtoryBinTree(pRoot->_pRight);//销毁右子树
			delete pRoot;//销毁根节点
			pRoot = NULL;
		}
	}
	void _PreOrder(pNode pRoot)//前序递归
	{
		if (pRoot)
		{
			cout << pRoot->_data << " ";
			_PreOrder(pRoot->_pLeft);
			_PreOrder(pRoot->_pRight);
		}
	}
	void _InOrder(pNode pRoot)//中序递归
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << pRoot->_data << " ";
			_InOrder(pRoot->_pRight);
		}
	}
	void _PostOrder(pNode pRoot)//后序递归
	{
		if (pRoot)
		{
			_PostOrder(pRoot->_pLeft);
			_PostOrder(pRoot->_pRight);
			cout << pRoot->_data << " ";
		}
	}
	void _LevelOrder(pNode pRoot)//中序
	{
		if (NULL == pRoot)
			return;
		queue<pNode> q;
		q.push(pRoot);
		while (!q.empty())
		{
			pNode pCur = q.front();
			cout << pCur->_data << " ";
			q.pop();

			if (pCur->_pLeft)
				q.push(pCur->_pLeft);
			if (pCur->_pRight)
				q.push(pCur->_pRight);
		}
	}
	size_t _Size(pNode pRoot)//结点个数
	{//左子树结点个数+右子树结点个数+1
		if (pRoot == NULL)
			return 0;
		return _Size(pRoot->_pLeft) + _Size(pRoot->_pRight) + 1;
	}
	size_t _GetLeafCount(pNode pRoot)//叶子结点个数
	{//左子树叶子结点个数+右子树叶子结点个数
		if (pRoot == NULL)
			return 0;
		if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
			return 1;
		return _GetLeafCount(pRoot->_pLeft) + _GetLeafCount(pRoot->_pRight);
	}
	size_t _GetLevelCount(pNode pRoot, size_t K)//第K层
	{
		if (K == 0 || pRoot == NULL)//size_t是大于等于0的,不用考虑小于0
			return 0;
		if (K == 1)
			return 1;
		return _GetLevelCount(pRoot->_pLeft, K - 1) + _GetLevelCount(pRoot->_pRight, K - 1);
	}
	size_t _Height(pNode pRoot)//高度
	{
		if (pRoot == NULL)
			return 0;
		if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
			return 1;
		size_t leftNode = _Height(pRoot->_pLeft);

		return _Height(pRoot->_pRight) > leftNode ? _Height(pRoot->_pRight) + 1 : leftNode + 1;
	}
	pNode _Find(pNode pRoot, const T& data)//查找值为data的结点
	{
		if (NULL == pRoot)
			return NULL;
		if (pRoot->_data == data)
			return pRoot;

		pNode tmp = _Find(pRoot->_pLeft, data);//先在根找,根没找到,再去左子树找,找到直接返回,没找到再去右子树
		return (NULL == tmp) ? _Find(pRoot->_pRight, data) : tmp;
	}
	pNode _Parent(pNode pRoot, pNode PNode)//找双亲结点
	{
		if (NULL == pRoot || pRoot == PNode || PNode == NULL)
			return NULL;
		if (pRoot->_pLeft == PNode || pRoot->_pRight == PNode)
			return pRoot;

		pNode tmp = _Parent(pRoot->_pLeft, PNode);
		return (NULL == tmp) ? _Parent(pRoot->_pRight, PNode) : tmp;
	}
	void _Mirror(pNode pRoot)//镜像
	{
		if (NULL == pRoot)
			return;
		if (pRoot->_pLeft || pRoot->_pRight)
			swap(pRoot->_pLeft, pRoot->_pRight);
		_Mirror(pRoot->_pLeft);
		_Mirror(pRoot->_pRight);
	}
private:
	pNode _pRoot;
};
下面是我的测试函数:

void Test()
{
	char* pStr = "abd###ce##f";
	BinTree<char> bt(pStr, strlen(pStr), '#');
	if (bt.IsCompleteBinTree())
		cout << "是完全二叉树" << endl;
	else
		cout << "不是完全二叉树" << endl;
	bt.PreOrder();
	bt.Mirror();
	bt.Mirror_N();
	bt.PreOrder();
	bt.PostOrder_N();
	bt.PreOrder_N1();
	bt.PreOrder_N2();
	bt.InOrder_N();
	bt.PreOrder();
	bt.LevelOrder();
	bt.InOrder();
	bt.PostOrder();
	cout << bt.Size() << endl;
	cout << bt.GetLeafCount() << endl;
	cout << bt.Height() << endl;

	BinTreeNode<char>* pcur = bt.Parent(bt.Find('b'));
	cout << pcur->_data << endl;
	cout << bt.LeftChild(bt.Find('a'))->_data << endl;
	cout << bt.LeftChild(bt.Find('b'))->_data << endl;
	if (bt.RightChild(bt.Find('b')))
		cout << bt.RightChild(bt.Find('b'))->_data << endl;
	cout << bt.LeftChild(bt.Find('c'))->_data << endl;
	cout << bt.RightChild(bt.Find('c'))->_data << endl;
	cout << bt.GetKLevelCount(1) << endl;
	cout << bt.GetKLevelCount(2) << endl;
	cout << bt.GetKLevelCount(3) << endl;

	BinTree<char> bt1(bt);
	bt1.PreOrder();
	BinTree<char> bt2;
	bt2 = bt;
	bt2.PreOrder();
}
这些函数基本都用到了递归+前序遍历或后序遍历的思想,有的借助到了栈或者队列,其实现方法并不复杂。
相关文章
相关标签/搜索