前言:
二叉树虽然是非线性结构,但二叉树的遍历却为二叉树的结点集导出了一个线性序列。对于 前、中、后序遍历,除了相应序列的第一个结点和最后一个节点,二叉树的遍历序列中每个 结点都有一个前驱和后继结点,但在二叉树中,无法很快的找出按照某种遍历序列该结点的前驱和后继。
在二叉树中希望很快找到某一节点的前驱或后继,而不希望每次都要对二叉树遍历一遍,因此 在创建二叉树的过程中,需要将每个结点的前驱和后继记录下来。我在此处处理的方法是加上一个标记。
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;
}
切记:线索化二叉树时有先序,中序和后序,当对二叉树遍历时,也有先序,中序和后序。遍历的方法要和线索化二叉树的方法要一致。