不知道你是否和我當時同樣,對於線索二叉樹,有點雲裏霧裏的感受,如今咱們來一塊兒探討下吧。函數
首先,咱們所應該知道的是:線索二叉樹是對二叉鏈表中空指針的充分利用,也就是說,使得本來是空指針的轉化成在某種遍歷的順序下,指向該結點的前驅和後繼。也許聽的有點糊塗,不要緊,請接着往下看。spa
在二叉鏈表中,每一個結點都帶有*leftChild和*rightChild,兩個指針,而除根結點外,每一個結點只被一個指針所對應,要麼是leftChild,要麼是rightChild.而總共有2*n個指針,也就是說,有2*n-(n-1)個空指針,從這個角度,也說明了線索二叉樹的必要性。指針
線索二叉樹在二叉鏈表的基礎上增長了兩個成員數據:leftTag,rightTag;用來標記當前結點的leftChild,rightChild指針指向的是孩子,仍是線索。leftTag=rightTag=1,表示線索,leftTag=rightTag=0;表示孩子;class
下面給出中序遍歷順序下的線索二叉樹的構造函數,*p爲根;基礎
template <class ElemType>二叉樹
void InThreadBinTree<ElemType>::InThreadHelp(ThreadBinTreeNode<ElemType> *p,ThreadBinTreeNode<ElemType> *pre)循環
{遍歷
if(p!=NULL)構造函數
{程序
InThreadHelp(p->leftChild,pre);
if(p->leftChild==NULL)
{
p->leftChild=pre;
p->leftTag=1;
}
else
p->leftTag=0;
if(pre!=NULL&&pre->rightChild==NULL)
{
pre->rightChild=p;
pre->rightTag=1;
}
else if(pre!=NULL)
{
pre->rightTag=0;
}
pre=p;
InThreadHelp(p->rightChild,pre);
}
}
該段程序可被分爲3部分,1.左孩子的線索化,2.p的線索化,3.p右孩子的線索化。
在中序遍歷的前提下,判斷p是否有空指針,然而,再遍歷右子樹以前,若是p->rightChild=NULL是沒法肯定p的後繼的,所以,此時,只能判斷p->leftChild是否爲空,若爲空,則leftChild=pre;此時,判斷pre->rightChild是否爲空,如爲空,pre->rightChild=p;
p=pre;你也許注意到了,此時pre->rightChild,也就是先前p->rightChild,此時能夠判斷了,而且後繼就是如今的p;此時全部空指針的線索化已經完成。固然,第一個結點的leftchild,和最後一個結點的rightchild是空指針,由於他們不須要線索化。
那麼問題又來了,作了這麼多,線索二叉樹有什麼用,或者說要怎麼用。
如下是我的理解;
經過構造線索二叉樹,咱們能夠很容易肯定樹中任何一個結點在某種遍歷順序下的前驅或者後繼。不妨以中序遍歷爲例;
樹中必然存在這樣兩種結點:被線索化了的,以及沒有被線索化的
被線索化的,leftTag==1,leftchild即爲前驅,rightTag==1,rightChild即爲後繼;
若leftTag==0,則該結點的前驅經過leftchild爲根的樹的rightchild循環,直到rightTag==1,即爲其前驅,
若rightTag==0,則經過rightchild爲根的leftchild循環,直到leftTag==1,即爲其後繼。
也就是說,任何結點按中序遍歷的順序的前驅和後繼都能找到。這就是線索二叉樹的做用,方便肯定某種遍歷的順序。