線索二叉樹(shù)實(shí)質(zhì)上就是將一顆二叉樹(shù)轉(zhuǎn)化成二叉鏈表的過(guò)程,將二叉樹(shù)的一些空指針給利用起來(lái),為了達(dá)到這個(gè)目的,我們使用中序遍歷線索化的辦法。
也就是要將每個(gè)節(jié)點(diǎn)的指針全部存儲(chǔ)一個(gè)值,為了區(qū)分線索和真正的子節(jié)點(diǎn),我們就需要一個(gè)flag,將線索和子節(jié)點(diǎn)區(qū)分開(kāi)來(lái),具體代碼如下。
#define thread 1
#define child 0
//我們將原本的節(jié)點(diǎn)擴(kuò)充一下,來(lái)區(qū)分指針存儲(chǔ)的是什么
struct treeNode
{
int data;
treeNode* lChild;
treeNode* rChild;
int lTag;
int rTag;
};
//定義一個(gè)全局變量,指向上一次遍歷過(guò)的節(jié)點(diǎn)
//我們需要在每次遞歸線索化的時(shí)候改變這個(gè)值
//也可以不需要全局變量,改用引用
treeNode* preNode;
//中序線索化二叉樹(shù)
void cueingTree(treeNode* node)
{
if(node != NULL)
{
cueingTree(node->lChild);
//如果當(dāng)前節(jié)點(diǎn)的左子樹(shù)節(jié)點(diǎn)是為NULL,則說(shuō)明它可以用來(lái)存放這個(gè)節(jié)點(diǎn)的前驅(qū)
//即上次遍歷過(guò)的節(jié)點(diǎn)
if(node->lChild == NULL)
{
node->lTag = thread;
node->lChild = preNode;
}
//如果上個(gè)節(jié)點(diǎn)的右子樹(shù)為NULL,說(shuō)明可以存放這個(gè)節(jié)點(diǎn)的后繼
//只有在知道了后繼之后才能為前一個(gè)節(jié)點(diǎn)賦值
if(preNode->rChild == NULL)
{
preNode->rTag = thread;
preNode->rChild = node;
}
//更新上次遍歷過(guò)的節(jié)點(diǎn)
preNode = node;
if(node->rChild != node)
{
cueingTree(node->rChild);
}
}
}
//在有了線索二叉樹(shù)之后,我們便可以使用迭代的方式來(lái)遍歷二叉樹(shù)
void inOrderTraversal()
{
treeNode* currentNode = this->head->lChild;
while(currentNode != this->head)
{
while(currentNode->lTag == child)
{
currentNode = currentNode->lChild;
}
cout << currentNode->data << " ";
while(currentNode->rTag == thread && currentNode->rChild != this->head)
{
currentNode = currentNode->rChild;
cout << currentNode->data << " ";
}
currentNode = currentNode->rChild;
}
}
其實(shí)線索二叉樹(shù)的建立過(guò)程,就是一次中序遍歷的過(guò)程,在遍歷過(guò)程中,對(duì)每一個(gè)節(jié)點(diǎn)進(jìn)行線索化,如果有能利用到的空指針,就可以用來(lái)存放前驅(qū)后繼。