二叉树虽然是非线性结构,但二叉树的遍历却为二叉树的结点集导出了一个线性序列。对于前、中、后序遍历,除了相应序列的第一个结点和最后一个节点,二叉树的遍历序列中每个结点都有一个前驱和后继结点,但在二叉树中,无法很快的找出按照某种遍历序列该结点的前驱和后继
在二叉树中希望很快找到某一节点的前驱或后继,而不希望每次都要对二叉树遍历一遍,因此在创建二叉树的过程中,需要将每个结点的前驱和后继记录下来。
当某节点的左指针为空时,令该指针指向按照某种方式遍历二叉树时得到该节点的前驱结点;当某节点的右指针为空时,令该指针指向按照某种方式遍历二叉树时得到该节点的后继结点。但问题是无法区分:左指针指向的结点是左孩子结点还是前驱结点,右指针指向的结点是右孩子结点还是后继结点。因此需要增加两个线索标志位来区分这两种情况:
leftThread = 0;leftChild指向结点的左孩子结点
leftThread = 1;leftChild指向结点的前驱结点
rightThread = 0;rightChild指向结点的右孩子结点
rightThread = 1;rightChild指向结点的右孩子结点
结点中指向前驱结点和后继结点的指针称为线索,二叉树结点加上线索的二叉树称为线索二叉树,对二叉树以某种方式(前序、中序、后续)遍历使其变为线索二叉树的过程称为按照该方法对二叉树进行线索化。
其代码具体实现:
#PRagma once#include <iostream>using namespace std;enum ThdInfo{ LINK,THREAD };template <class T>struct BinaryTreeThrNode{BinaryTreeThrNode(const T& data):_data(data),_pLeft(NULL),_pRight(NULL),_pParent(NULL) //后续的遍历需要知道其父亲结点,_leftThd(LINK),_rightThd(LINK){}T _data;BinaryTreeThrNode<T>* _pLeft;BinaryTreeThrNode<T>* _pRight;BinaryTreeThrNode<T>* _pParent;ThdInfo _leftThd;ThdInfo _rightThd;};template<class T>class BinaryTreeThr{public:BinaryTreeThr():_pRoot(NULL){}BinaryTreeThr(T arr[],size_t size){size_t idx = 0;_GreatBinaryTree(_pRoot,arr,size,idx);}//前序线索化void PreThread(){BinaryTreeThrNode<T>* pre = NULL;_PreThread(_pRoot,pre);}//前序遍历void PreTraverseThr(){_PreTraverseThr(_pRoot);}//中序线索化void InThread(){BinaryTreeThrNode<T>* pre = NULL;_InThread(_pRoot,pre);}//中序遍历void InTraverseThr(){_InTraverseThr(_pRoot);}//后续线索化void PostThread(){BinaryTreeThrNode<T>* pre = NULL;_PostThread(_pRoot,pre);}//后续遍历void _PostTraverseThr(){_PostTraverseThr(_pRoot);}private:void _PostTraveseThr(BinaryTreeThrNode<T>* pRoot){BinaryTreeThrNode<T>* pCur = pRoot;BinaryTreeThrNode<T>* prev = NULL;while(pCur){if(pCur->_pLeft != prev){while(LINK == pCur->_leftThd)pCur = pCur->_pLeft;}while(pCur && THREAD == pCur->_pRight){cout<<pCur->_data<<" ";prev = pCur;pCur = pCur->_pRight;}if(pCur == pRoot && pCur->_pRight == prev){cout<<pCur->_data<<" ";return;}while(pCur && pCur->_pRight == prev){cout<<pCur->_data<<" ";prev = pCur;pCur = pCur->_pParent;}if(pCur && pCur->_rightThd == LINK){pCur = pCur->_pRight;}}}//后续线索化void _PostThread(BinaryTreeThrNode<T>* pRoot,BinaryTreeThrNode<T>*& prev){if(pRoot){_PostThread(pRoot->_pLeft,prev);_PostThread(pRoot->_pRight,prev);if(NULL == pRoot->_pLeft){pRoot->_leftThd = THREAD;pRoot->_pLeft = prev;}if(prev && NULL = prev->_pRight){prev->_rightThd = THREAD;prev->_pRight = pRoot;}prev = pRoot;}}//中序遍历void _InTraverseThr(BinaryTreeThrNode<T>* pRoot){BinaryTreeThrNode<T>* pre = pRoot;while(pre){while(LINK == pre->_leftThd){pre = pre->_pLeft;}while(pre){cout<<pre->_data<<" ";if(THREAD == pre->_rightThd){pre = pre->_pRight;}else{pre = pre->_pRight;break;}}}}//中序线索化void _InThread(BinaryTreeThrNode<T>* pRoot,BinaryTreeThrNode<T>*& prev){if(pRoot)//找到最左边的孩子(根节点){_InThread(pRoot->_pLeft,prev);if(NULL == pRoot->_pLeft){pRoot->_pLeft = prev;pRoot->_leftThd = THREAD;}if(prev && NULL == prev->_pRight){prev->_pRight = pRoot;prev->_rightThd = THREAD;}prev = pRoot;if(LINK == pRoot->_rightThd)_InThread(pRoot->_pRight,prev);}} //前序遍历 void _PreTraverseThr(BinaryTreeThrNode<T>* pRoot){BinaryTreeThrNode<T>* pCur = pRoot;while(pCur){//访问所有最左边的孩子while(LINK == pCur->_leftThd){cout<<pCur->_data<<" ";pCur = pCur->_pLeft;}cout<<pCur->_data<<" ";pCur = pCur->_pRight; }cout<<endl;} //前序线索化void _PreThread(BinaryTreeThrNode<T>* pRoot,BinaryTreeThrNode<T>*& prev){if(pRoot){if(NULL == pRoot->_pLeft){pRoot->_pLeft = prev;pRoot->_leftThd = THREAD;}if(prev && NULL == prev->_pRight){prev->_pRight = pRoot;prev->_rightThd = THREAD; }prev = pRoot;if(LINK == pRoot->_leftThd){_PreThread(pRoot->_pLeft,prev);}if(LINK == pRoot->_rightThd){_PreThread(pRoot->_pRight,prev);}}}//创建二叉树void _GreatBinaryTree(BinaryTreeThrNode<T>*& pRoot,T arr[], size_t size, size_t& idx){if(idx<size && arr[idx]!='#'){pRoot = new BinaryTreeThrNode<T>(arr[idx]);_GreatBinaryTree(pRoot->_pLeft,arr,size,++idx);if(pRoot->_pLeft)pRoot->_pLeft->_pParent = pRoot;_GreatBinaryTree(pRoot->_pRight,arr,size,++idx);if(pRoot->_pRight)pRoot->_pRight->_pParent = pRoot;}}private:BinaryTreeThrNode<T>* _pRoot;};
新闻热点
疑难解答