线索化二叉树的构造及遍历

前言:

二叉树虽然是非线性结构,但二叉树的遍历却为二叉树的结点集导出了一个线性序列。对于 前、中、后序遍历,除了相应序列的第一个结点和最后一个节点,二叉树的遍历序列中每个 结点都有一个前驱和后继结点,但在二叉树中,无法很快的找出按照某种遍历序列该结点的前驱和后继。


在二叉树中希望很快找到某一节点的前驱或后继,而不希望每次都要对二叉树遍历一遍,因此 在创建二叉树的过程中,需要将每个结点的前驱和后继记录下来。我在此处处理的方法是加上一个标记。

enum PiontInfo
{
	LINK,//指向左右孩子
	THREAD,//指向前驱后继
};


结点中指向前驱结点和后继结点的指针称为线索,二叉树结点加上线索的二叉树称为线索 二叉树,对二叉树以某种方式(前序、中序、后续)遍历使其变为线索二叉树的过程称为按 照该方法对二叉树进行线索化

完整的代码如下:

#include<iostream>
#include<string.h>
using namespace std;
enum PiontInfo
{
	LINK,//指向左右孩子
	THREAD,//指向前驱后继
};

//节点
template<class T>
struct BinaryTreeThdNode{
	BinaryTreeThdNode(const T& value):_value(value),_pLeft(NULL),_pRight(NULL),
		                              _parent(NULL),_LeftThread(LINK),_RightThread(LINK)
	{
	}
	BinaryTreeThdNode<T>* _pLeft;//左孩子
	BinaryTreeThdNode<T>* _pRight;//右孩子
	BinaryTreeThdNode<T>* _parent;//双亲
	PiontInfo _LeftThread;
	PiontInfo _RightThread;
	T _value;
};

//树
template<class T>
class BinaryTreeThd
{
	typedef BinaryTreeThdNode<T> Node;
public:
	BinaryTreeThd():_pRoot(NULL)
	{}
	BinaryTreeThd(const T arr[],size_t size,const T& invalid)
	{
		size_t index=0;
	  _CreateBinaryTreeThd(_pRoot,arr,size,index,invalid);
	}
	//前序线索化
	void PreThread()
	{
	  Node* prev=NULL;
	  _PreThread(_pRoot,prev);
	}
	//中序线索化
	void InThread()
	{
	 Node* prev=NULL;
	 _InThread(_pRoot,prev);
	}
	//后序线索化
	void PostThread()
	{
	 Node* prev=NULL;
	 _PostThread(_pRoot,prev);

	}
   //前序遍历
	/*思路:找最左边的节点,访问路径上的节点
	        当前节点:存在右子树
			          右子树不存在:循环访问后继,*/
	void PreOrder()
	{
	 Node* pCur=_pRoot;
	 while(pCur)
	 {
		 while(LINK==pCur->_LeftThread)
		 {
			 cout<<pCur->_value<<" ";
			 pCur=pCur->_pLeft;
		 }
		 cout<<pCur->_value<<" ";
		 while(THREAD==pCur->_RightThread)
		 {
			 pCur=pCur->_pRight;
			 cout<<pCur->_value<<" ";
			 
		 }
		 if(LINK==pCur->_LeftThread)//左子树存在
			 pCur=pCur->_pLeft;
		 else  //左子树不存在,访问右子树
			 pCur=pCur->_pRight;
	 }
	}
	/*void PreOrder()
	{
	 Node* pCur=_pRoot;
	 while(pCur)
	 {
		while(LINK==pCur->_LeftThread)
		 {
			 cout<<pCur->_value<<" ";
			 pCur=pCur->_pLeft;
		 }
		 cout<<pCur->_value<<" ";

		 pCur=pCur->_pRight;
	 }
	}*/
	//中序遍历
	/*思路:找最左边的节点,访问
	        当前节点的右子树不存在:访问后继
			                存在:当成树,再次循环访问*/
	void InOrder()
	{
	  Node* pCur=_pRoot;
	  while(pCur)
	  {
		  while(LINK==pCur->_LeftThread)
		  {
			  pCur=pCur->_pLeft;
		  }
		  cout<<pCur->_value<<" ";
		  while(THREAD==pCur->_RightThread)
		  {
			  pCur=pCur->_pRight;
			  cout<<pCur->_value<<" ";
		  }
		  pCur=pCur->_pRight;
	  }
	}
	//后序遍历
	/*思路:找最左边的节点,访问
	         当前节点的右子树存在,当成树
			                 不存在,访问*/
	void PostOrder()
	{
	  if(NULL==_pRoot)
		  return;
	  Node* pCur=_pRoot;
	  Node* prev=NULL;
	  while(pCur)
	  {
	   //当前节点左子树没有访问
	   if(prev!=pCur->_pLeft)
	   {
		   while(pCur->_LeftThread==LINK)
		   {
			   pCur=pCur->_pLeft;
		   }
	   }
	   //访问连在一起的后继
	   while(pCur->_RightThread==THREAD)
	   {
		   cout<<pCur->_value<<" ";
		   prev=pCur;
		   pCur=pCur->_pRight;
	   }
	   //左单支
	   if(pCur==_pRoot && pCur->_pRight==NULL)
	   {
		   cout<<pCur->_value<<" ";
		   return;
	   }
	   //右单支
	   while(pCur && pCur->_pRight==prev)
	   {
		   cout<<pCur->_value<<" ";
		   prev=pCur;
		   pCur=pCur->_parent;
	   }
	   //右子树存在
	   if(pCur && LINK==pCur->_RightThread)
	   {
		   pCur=pCur->_pRight;
	   }
	  }
	
	}
//-------------------------------------------------------------------
private:
	//前序线索化
	void _PreThread(Node* pRoot ,Node*& prev)
	{
	 if(pRoot)
	 {
		 //线索化当前节点的左指针域
		if(NULL==pRoot->_pLeft)
		{
			pRoot->_pLeft=prev;//指向前驱
			pRoot->_LeftThread=THREAD;
		}
	  //线索化上一节点的右指针域
		if(prev && NULL==prev->_pRight)
		{
			prev->_pRight=pRoot;//指向后继
			prev->_RightThread=THREAD;
		}
	   
		prev=pRoot;
		if(LINK==pRoot->_LeftThread) 
			_PreThread(pRoot->_pLeft ,prev);
		if(LINK==pRoot->_RightThread)
			_PreThread(pRoot->_pRight ,prev);
	 }
	}
	//中序线索化
	void _InThread(Node* pRoot ,Node*& prev)
	{
	 if(pRoot)
	 {
		//左子树
		_InThread(pRoot->_pLeft ,prev);

		 //线索化当前节点的左指针域
		if(NULL==pRoot->_pLeft)
		{
			pRoot->_pLeft=prev;//指向前驱
			pRoot->_LeftThread=THREAD;
		}
	  //线索化上一节点的右指针域
		if(prev && NULL==prev->_pRight)
		{
			prev->_pRight=pRoot;//指向后继
			prev->_RightThread=THREAD;
		}
	   
		prev=pRoot;

		//右子树
		if(LINK==pRoot->_RightThread)
			_InThread(pRoot->_pRight ,prev);
	 }
	}
	//后序线索化
	void _PostThread(Node* pRoot ,Node*& prev)
	{
	 if(pRoot)
	 {
		//左子树
		_PostThread(pRoot->_pLeft ,prev);

		
		//右子树
		_PostThread(pRoot->_pRight ,prev);

		 //线索化当前节点的左指针域
		if(NULL==pRoot->_pLeft)
		{
			pRoot->_pLeft=prev;//指向前驱
			pRoot->_LeftThread=THREAD;
		}
	  //线索化上一节点的右指针域
		if(prev && NULL==prev->_pRight)
		{
			prev->_pRight=pRoot;//指向后继
			prev->_RightThread=THREAD;
		}
	   
		prev=pRoot;
	 }
	}
	//创建树
	void  _CreateBinaryTreeThd(Node*& pRoot,const T arr[],size_t size,size_t &index,const T& invalid)
	{
	  if(index<size && arr[index]!=invalid)
	  {
	     pRoot=new Node(arr[index]);
	     _CreateBinaryTreeThd(pRoot->_pLeft,arr,size,++index,invalid);
		 if(pRoot->_pLeft)
			 pRoot->_pLeft->_parent=pRoot;
		 _CreateBinaryTreeThd(pRoot->_pRight,arr,size,++index,invalid);
		 if(pRoot->_pRight)
			 pRoot->_pRight->_parent=pRoot;
	  }
	}
private:
   Node* _pRoot;
};

测试代码如下:

#include "BinaryTreeThd.hpp"

void Fun1()
{
	char* str="124###35##6";
	BinaryTreeThd<char> bt(str,strlen(str),'#');
	/*bt.PreThread();
	bt.PreOrder();*/
	/*bt.InThread();
	bt.InOrder();*/
	bt.PostThread();
	bt.PostOrder();
}


int main()
{
	Fun1();

 return 0;
}

切记:线索化二叉树时有先序,中序和后序,当对二叉树遍历时,也有先序,中序和后序。遍历的方法要和线索化二叉树的方法要一致。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值