二叉树及其操作

为了实现后序线索化二叉树    多加了_parent指针域 但是没有更改其拷贝构造函数

先来研究线索化原因:   n个节点对应2n个指针域   有效指针域n-1个(根节点没有)   所以无效指针域2n-(n-1)个而线索化就是把                                         这些空的指针域链接到其对应的前驱或者后继

对应三种线索化;前/中序/后

#include<iostream>
#include<queue>
#include<stack>
using namespace std;
template<class T>
class TreeNode
{
public:
	TreeNode(T data)
		:_left(NULL)
		, _right(NULL)
		, _parent(NULL)
		, _val(data)
		, Ltag(0)
		, Rtag(0)
		{}
	//TreeNode<T>* _parent;
	TreeNode<T>* _left;
	TreeNode<T>* _right;
	TreeNode<T>* _parent;
	bool Ltag;          // 1为链接的前驱和后继  0对应 左孩子右孩子
	bool Rtag;
	T _val;
};
template<class T>
class BTree
{
public:
	typedef TreeNode<T> Node;
	typedef Node* PNode;
	BTree()
		:_pHead(NULL)
	{}
	//数组构造二叉树
	BTree(T* array, size_t size, T invalid)
	{
		size_t index = 0;
		PNode parent = NULL;
		CreateBTree(_pHead,array, size, index, invalid,parent);
	}
   //拷贝构造(深拷贝) 
	BTree(const BTree& bt)
	{
		_pHead = copyBTree(bt._pHead);
	}
	//赋值运算符重载
	BTree& operator=(const BTree& bt)
	{
		if (this != &bt)     //不是自拷贝
		{
			//1.0 析构自己
			this->~BTree();
			//2.0 深拷贝调拷贝构造函数
			this->_pHead=this->copyBTree(bt._pHead);
		}
		return *this;
	}
	//递归遍历
	void PreOrder1()  
	{ 
		cout << "递归先序遍历:";
		_PreOrder1(_pHead);
		cout << "NULL" << endl;
	}
	void InOrder1()
	{
		cout << "递归中序遍历:";
		_InOrder1(_pHead);
		cout <<"NULL"<<endl;
	}
	void PostOrder1()
	{
		cout << "递归后序遍历:";
		_PostOrder1(_pHead);
		cout << "NULL" << endl;
	}
	void LevelOrder1()
	{
		cout << "递归层序遍历:";
		_LevelOrder1(_pHead);
		cout << "NULL" << endl;
	}
	//非递归遍历
	void PreOrder2()
	{
		cout << "非递归先序遍历:";
		_PreOrder2(_pHead);
	}
	void InOrder2()
	{
		cout << "非递归先序遍历:";
		_InOrder2(_pHead);
	}
	void PostOrder2()
	{
		cout << "非递归先序遍历:";
		_PostOrder2(_pHead);
	}
	void LevelOrder2()
	{
		cout << "非递归先序遍历:";
		_LevelOrder2(_pHead);

	}
	//树的深度
	size_t Depth()
	{
		return _Depth(_pHead);
	}
	bool Is_completeBTree()
	{
		cout <<"是不是完全二叉树" ;
		return Is_completeBTree(_pHead);
	}
	size_t GetLevelKNodeNum(size_t k)
	{
		cout << "第"<<k<<"层节点个数:";
		return _GetLevelKNodeNum(_pHead,k);
	}
	size_t NodeSize()
	{
		/*return NodeSize1(_pHead);*/  //方式1
		return NodeSize2(_pHead);      //方式2
	}
	size_t LeafSize()
	{
		cout << "叶子节点个数:";
		return LeafSize(_pHead);
	}
	PNode Find_data_isK(T& data)
	{
		cout << "查找值为"<<data<<"的节点:";
		return Find_data_isK(_pHead,data);
	}
	//节点是否再二叉树中
	bool InBTree(PNode node)
	{
		cout << "节点是否在二叉树中:";
		return InBTree(_pHead,node);
	}
	//是否为满二叉树
	bool Is_FullBTree()
	{
		cout << "是否为满二叉树" << " ";
		return Is_FullBTree(_pHead);
	}
	//前序线索化二叉树     2n个指针域  有效的只有n-1个根节点没有  NULL节点个数2*n-(n-1)
	void PreThreadBTree() 
	{
		PNode node = NULL;
	    _PreThreadBTree(_pHead,node);
	}
	//前序线索化二叉树非递归遍历
	void PreOrderThreadNor()
	{
		_PreOrderThreadNor(_pHead);
	}
	//中序线索化二叉树
	void InThreadBTree()
	{
		PNode node = NULL;
		InThreadBTree(_pHead, node);
	}
	//中序非递归遍历线索化的二叉树
	void InOrderThreadNor()
	{
		_InOrderThreadNor(_pHead);
	}
	//后序线索化二叉树
	void PostThreadBTree()
	{
		PNode Pre = NULL;
		PostThreadBTree(_pHead,Pre);
	}
	//后序线索化二叉树非递归遍历
	void PostOrderThreadNor()
	{
		_PostOrderThreadNor(_pHead);
	}
protected:
	//先序创建二叉树
    void CreateBTree(PNode& root,T* array, size_t size, size_t& index, T invalid,PNode& parent)
	{
	    if (index < size&&array[index] != invalid)
	    {
		  root = new Node(array[index]);
		  root->_parent = parent;
          CreateBTree(root->_left,array,size, ++index, invalid,root);
		  CreateBTree(root->_right,array, size, ++index, invalid,root);
	     }
    }
	//先序拷贝二叉树
	PNode copyBTree(PNode node)
	{
		if (NULL == node)
			return NULL;
		PNode newnode = new Node(node->_val);
		newnode->_left = copyBTree(node->_left);
		newnode->_right = copyBTree(node->_right);
		return newnode;
	}
	//前序线索化二叉树
	void _PreThreadBTree(PNode root,PNode& Pre)
	{
		if (NULL == root)
			return;
		//线索化当前节点左孩子
		if (NULL == root->_left)
		{
			root->_left = Pre;
			root->Ltag = 1;
		}
		//线索化前一个节点的右孩子
		if (NULL != Pre&&NULL == Pre->_right)
		{
			Pre->_right = root;
			Pre->Rtag = 1;
		}
		else if (Pre != NULL)
			Pre->Rtag = 0;
		Pre = root;
		if (root->Ltag==0)
			_PreThreadBTree(root->_left,Pre);
		if (root->Rtag==0)
		    _PreThreadBTree(root->_right,Pre);
	}
	//前序线索化二叉树非递归遍历
	void _PreOrderThreadNor(PNode root)
	{
		PNode pCur = root;
		while (pCur)
		{
			while (pCur->Ltag == 0)   //左孩子的情况        打印左单支
			{
				cout <<pCur->_val<< "->";
				pCur=pCur->_left;
			}
            //pCur_>Ltag==1;         //左线索
			cout << pCur->_val << "->"; 
			pCur = pCur->_right;              //右孩子还是右线索都来到这里
		}
		cout <<"NULL"<<endl;
	}
	//中序线索化二叉树---第二个参数用来保存中序遍历上一个节点
	void InThreadBTree(PNode root,PNode& Pre)      //第一个节点前驱和最后一个节点后继不用线索化为NULL
	{
		if (root)
		{
			//1.0 左孩子线索化
			InThreadBTree(root->_left,Pre);          //线索化当前节点的左孩子和前一个节点的右孩子
			//2.0 root的线索化
			if (NULL == root->_left)
			{
				root->_left = Pre;
				root->Ltag = 1;
			}
			else
				root->Ltag = 0;    //可以没有因为初始化已默认经置为0
			//3.0 右孩子的线索化
			if (NULL != Pre&&NULL == Pre->_right)      //顺序
			{
				Pre->_right = root;
				Pre->Rtag = 1;
			}
			else if (NULL!= Pre)
				Pre->Rtag = 0;
			Pre = root;
			InThreadBTree(root->_right, Pre);
		}
	}
	//中序线索化二叉树非递归遍历
	void _InOrderThreadNor(PNode root)
	{
		if (NULL == root)
			return;
		PNode pCur = root;
		while (pCur)
		{
			while (pCur->Ltag==0&&pCur->_left)          //左孩子标志为1即线索时 往左下角走
			{
				pCur = pCur->_left;
			}
			cout << pCur->_val<<"->";
			while (pCur->Rtag == 1)                    //只要pCur的右孩子标志为1时为线索往后走
			{
				pCur = pCur->_right;
				cout << pCur->_val;
			}
			//pCur->Rtag == 0
			pCur=pCur->_right;
		}
		cout << "NULL"<<endl;
	}
	//后序线索化二叉树
	void PostThreadBTree(PNode root,PNode& Pre)
	{
		if (NULL == root)
			return;
		PostThreadBTree(root->_left,Pre);             //左孩子线索化
		PostThreadBTree(root->_right,Pre);            //右孩子线索化
		if (NULL == root->_left)                  //线索化当前节点左孩子
		{
			root->_left = Pre;
			root->Ltag = 1;
		}
		if (NULL != Pre&&NULL == Pre->_right)     //线索化前一个节点右孩子
		{
			Pre->_right = root;
			Pre->Rtag = 1;
		}
		else if (NULL != Pre)
			Pre->Rtag = 0;
		Pre = root;          //更新Pre
	}
	//后序线索化二叉树的非递归遍历
	void _PostOrderThreadNor(PNode root)
	{
		if (NULL == root)
			return;
		PNode pCur = root;
		PNode Pre = NULL;
		while(pCur)
		{
			//1.0 走到最左侧节点
			while (pCur->_left != Pre&&pCur->Ltag == 0)         //每次把pCur更新到parent时其左子树已经遍历过了
			{                                                   //所以需要pCur->_left!=Pre;
				pCur = pCur->_left;                            
			}
			//循环结束后在最左侧节点因为最左侧节点被线索化了  pCur->Ltag == 1
			//pCur到后序遍历的起点
			pCur = pCur->_left;
            //2.0 找第一个后序遍历的节点
			while (pCur->Rtag == 1)  //线索了的右孩子   
			{                                                  
				cout <<pCur->_val<< "->";
				Pre = pCur;
				pCur = pCur->_right;
			}
			//3.0判断是不是到了根节点
			if (pCur == root)
			{
				cout << pCur->_val << "->";
				return;
			}
			//4.0 循环遍历当前结点并更新为其双亲节点
			while(pCur&&Pre== pCur->_right)           //右单支的情况
			{
				cout << pCur->_val << "->";
				Pre = pCur;
				pCur = pCur->_parent;
			}
			//5.0 Pre!= pCur->_right 即pCur->_left==Pre,pCur->Rtag==0
			if (pCur&&pCur->Rtag == 0&&pCur->_right!=NULL)             //不加条件3可能会出现头不打印的情况
			{
				pCur = pCur->_right;
			}
			else if (pCur&&pCur->Rtag == 0)  //pCur指向头
			{
				cout << pCur->_val << "->"<<"NULL";        
				return;
			}
		}
		cout << "NULL";
	}
	//递归先序遍历
	void _PreOrder1(PNode root)
	{
		if (root)
		{
			cout <<root->_val<< "-->";
			_PreOrder1(root->_left);
			_PreOrder1(root->_right);
		}
	}
	//递归中序遍历
	void _InOrder1(PNode root)
	{
		if (root)
		{
			_InOrder1(root->_left);
			cout << root->_val << "-->";
			_InOrder1(root->_right);
		}
	}
	//递归后序遍历
	void _PostOrder1(PNode root)
	{
		if (root)
		{
			_PostOrder1(root->_left);
			_PostOrder1(root->_right);
			cout << root->_val << "-->";
		}
	}
	//递归层序遍历  ---思想问题规模减小root的第k层节点   root下一层的k-1层      
	void  levelorderK(PNode node, size_t K)                     //第k层的遍历
	{
		if (K == 0 || NULL==node)
			return;
		if (K == 1)                          //该节点在所要求的层上
		{
			cout <<node->_val<< "-->";
			return;
		}
		levelorderK(node->_left, K-1);
		levelorderK(node->_right,K-1);
	}
	void _LevelOrder1(PNode root)
	{
		if (NULL == root)
			return;
		size_t depth = _Depth(root);
		for (size_t i = 1; i <=depth; ++i)
		{
			levelorderK(root, i);         //i代表层数
		}
	}
    //非递归先序遍历
	void _PreOrder2(PNode root)
	{
		stack<PNode> s;
		PNode pCur;
		if (root)
		  s.push(root);
		while (!s.empty())
		{
			pCur=s.top();
			cout <<pCur->_val<< "-->";
			s.pop();
			if (pCur->_right)         //先压右孩子后左孩子才能保证栈顶始终是左单支的节点
				s.push(pCur->_right);
			if (pCur->_left)
				s.push(pCur->_left);
		}
		cout <<"NULL"<<endl;
	}
	//非递归中序遍历
	void _InOrder2(PNode root)
	{
		stack<PNode> s;         //此处不先压栈root是为了在左单支入栈时条件简单
		PNode pCur = root;         
		while (pCur || !s.empty())
		{
			while (pCur)
			{
				s.push(pCur);
				pCur = pCur->_left;
			}
			pCur = s.top();
			cout <<pCur->_val<< "-->";
			s.pop();
			pCur = pCur->_right;
		}
		cout <<"NULL"<<endl;
	}
	//非递归后序遍历
	void _PostOrder2(PNode root)
	{
		stack<PNode> s;
		PNode pCur = root;
		PNode Pre = NULL;
		PNode pTop = NULL;
		while (pCur || !s.empty())
		{
			while (pCur)     //为了避免多次圧入重复节点  在栈顶_right为空的情况下 pCur一直保持NULL
			{
				s.push(pCur);
				pCur = pCur->_left;
			}
			pTop = s.top();
			if (NULL == pTop->_right || Pre == pTop->_right) //这里不能用pCur来做循环条件同一个pCur会被多次圧入
			{
				cout << pTop->_val << "-->";
				s.pop();
				Pre = pTop;
			}
			else
				pCur = pTop->_right;
		}
		cout <<"NULL"<<endl;
	}
	//非递归层序遍历
	void _LevelOrder2(PNode root)
	{
		queue<PNode> q;
		if (root)
		   q.push(root);
		size_t size = 0;
		PNode pCur = NULL;
		while (!q.empty()) 
		{
			//size=q.size();          //size表示当前层的节点数目
			//while (size--)          //这个适用于分层打印
			//{
			//	pCur = q.front();
			//	cout <<pCur->_val<< "-->";
			//	q.pop();
			//	if (pCur->_left)
			//		q.push(pCur->_left);
			//	if (pCur->_right)
			//		q.push(pCur->_right);
			//}
			pCur = q.front();
			cout <<pCur->_val<< "-->";
			q.pop();
    	    if (pCur->_left)
     		   q.push(pCur->_left);
			if (pCur->_right)
			   q.push(pCur->_right);

		}
		cout <<"NULL"<<endl;
	}
	size_t _Depth(PNode root)
	{
		if (NULL == root)
			return 0;
		size_t leftsize = _Depth(root->_left);
		size_t rightsize = _Depth(root->_right);
		return leftsize > rightsize ? leftsize + 1 : rightsize + 1;
	}
	//层序遍历 当前层 NULL之后如果有非空节点
	bool Is_completeBTree(PNode root)
	{
		queue<PNode> q;
		q.push(root);
		PNode pCur = root;
		//1.0 将所有的元素入队列包括NULL节点  只要队头为NULL那就退出循环判断后面有没有非空节点   有则不是没有则是
		while (pCur)
		{
			q.pop();
			q.push(pCur->_left);
		    q.push(pCur->_right);
			pCur = q.front();
		}
		while (!q.empty())
		{
			if (NULL == q.front())
				q.pop();
			else              //有非空节点
				return false;

		}
		//pCur为空--队头为空  q为空
		return true;
	}
	//得到第k层节点个数
	size_t _GetLevelKNodeNum(PNode root,size_t k)
	{
		if (k == 0 || NULL == root)
			return 0;
		if (k == 1)                    //该节点在所要求的层上
			return 1;
		return _GetLevelKNodeNum(root->_left,k-1)+_GetLevelKNodeNum(root->_right,k-1);
	}
	//二叉树节点个数
	size_t NodeSize1(PNode root)
	{
		if (NULL == root)
			return 0;
		size_t depth = _Depth(root);
		size_t count= 0;
		for (size_t i = 1; i <= depth; ++i)
		{
			count += _GetLevelKNodeNum(root, i);         //i代表层数
		}
		return count;
	}
	size_t NodeSize2(PNode root)
	{
		if (NULL == root)
			return 0;
           
		return NodeSize2(root->_left)+NodeSize2(root->_right)+1;
	}
	//叶子节点个数
	size_t LeafSize(PNode root)
	{
		if (NULL == root)
			return 0;
		if (NULL == root->_left&&NULL == root->_right);
		    return 1;
	    return LeafSize(root->_left) + LeafSize(root->_right);
	}
	PNode Find_data_isK(PNode root, T& data)
	{
		if (root == NULL)
			return NULL;
		if (root->_val == data)
			return root;
		PNode temp = NULL;
		if (root->_left)               //先序遍历找
			temp=Find_data_isK(root->_left, data);
		if (temp)      //左子树找到了
			return temp;
		return Find_data_isK(root->_right, data);	  //左子树找不到走右子树
	}
	//二叉树里是否有该节点
	bool InBTree(PNode root,PNode node)
	{
		if (root == NULL || node == NULL)
			return false;
		if (root == node)
			return true;
		//有true结果为true
		return InBTree(root->_left,node) || InBTree(root->_right,node);
	}
	//判断二叉树是否为满二叉树 k层对应2^k+1个节点
	bool Is_FullBTree(PNode root)
	{
		size_t depth = Depth();
		size_t nodesize=NodeSize();
		/*cout<<"满二叉树节点应为"<<pow(2, depth) - 1 << "个 ";*/
		return (pow(2,depth)-1)==nodesize;
	}
private:
	PNode _pHead;
};
void BTreeTest()
{
	char arr[7] = { 'A', 'C', '#', 'B', '#', '#', '#' };
	BTree<char> bt(arr, sizeof(arr) / sizeof(arr[0]), '#');
	//BTree<char> bt1(bt);
	//BTree<char> bt2;
	//bt2 = bt1;
	//bt2.PreOrder1();
	//bt2.InOrder1();
	//bt2.PostOrder1();
	//bt2.LevelOrder1();
	//cout << endl;
	//bt2.PreOrder2();
	//bt2.InOrder2();
	//bt2.PostOrder2();
	//bt2.LevelOrder2();
	//cout << "Depth:";
	//cout << bt2.Depth() << endl;
	//cout << bt2.Is_completeBTree() << " ";
	//cout << bt2.GetLevelKNodeNum(1) << " ";
	//cout << bt2.GetLevelKNodeNum(3) << " ";
	//cout << bt2.GetLevelKNodeNum(3) << endl;
	//cout << "节点个数:";
	//cout << bt2.NodeSize() << " " << endl;
	//cout << bt2.LeafSize();
	//char a = 'B';
	//char v = 'V';
	//cout<<bt2.Find_data_isK(a)->_val<<" ";
	///*cout << bt2.Find_data_isK(v)->_val << " ";*/   //这个没法这么测 找不到返回的节点为NULL取其_val非法访问内存会出错
	//cout << bt2.InBTree(bt2.Find_data_isK(a)) << " ";
	//cout << bt2.InBTree(NULL) << " "<<endl;
	//cout << bt2.Is_FullBTree()<<" ";
	//char arr1[16] = "ABD##E##CF##G##";
	//BTree<char> bt4(arr1, sizeof(arr1) / sizeof(arr1[0]), '#');
	//cout << bt4.Is_FullBTree() << " ";
    //先序线索化检测
	//bt2.PreThreadBTree();
	//bt2.PreOrderThreadNor();
	//中序线索化检测
	//bt2.InThreadBTree();
    //bt2.InOrderThreadNor();
	//后续线索化检测
	//bt.PostThreadBTree();
	//bt.PostOrderThreadNor();
}

猜你喜欢

转载自blog.csdn.net/WhiskyCocktail/article/details/81587789