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

来源:互联网 发布:php 7 加密 编辑:程序博客网 时间:2024/05/22 13:52

前言:

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


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

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
原创粉丝点击