我们在创建二叉树时,每个结点都记录的左右孩子的地址,但却不知道前驱是谁,后继是谁。同时创建完会有很多空指针,为了方便记录下每个结点的前一个结点(前驱)和后一个结点(后继)是什么,便可以充分利用这些空指针域。
例如一个结点没有左孩子,即它的左孩子指针指向空,这时我们可以让它的左指针指向它的前驱,若这个结点也没有右孩子,则这个结点的右指针指向它的后继。
图示:(空心箭头实线指向前期,实心箭头虚线指向后继)
对于我们如何知道结点的左右指针是指向左右孩子还是前驱后继,我们可以用bool标志,如果有左(右)孩子就用Link为0标志,
如果没有左右孩子就用Thread为1标志说明左右指针指向前驱和后继。
和双向链表结构一样,我们需要在二叉树线索链表上添加一个头结点(不是第一个结点),并且令头结点的左指针指向根点,右指针指向中序序列中的最后一个结点。
同时将第一个结点的左指针和最后一个结点的右指针都指向头结点。
这样的结构我们可以从第一个结点往后继遍历,也可以从最后一个结点往前驱遍历。
图示:
代码详解:
#include<iostream>
using namespace std;
bool Link = false, Thread = true;
int flag = 0;
struct Tree
{
char data;
Tree *lchild, *rchlid;//左右孩子
bool LTag, RTal;//标志左右孩子是否存在
};
Tree *first;//头结点
Tree *root;//根
Tree *pre;//始终是线索化时的前一个结点;
//------------------------------------------------------------
//创建二叉树
void CreateTree(Tree *T)
{
char ch;
cin >> ch;
flag++;
if (ch == '#')//代表空,没有数值
T->data = '#';
else
{
first->rchlid = T;//使得first的右孩子指向最后一个结点
T->data = ch;
//------------------------------------------------------创建左子树
Tree *TL = new Tree();
T->lchild = TL;
CreateTree(T->lchild);
//------------------------------------------------------创建右子树
Tree *TR = new Tree();
T->rchlid = TR;
CreateTree(T->rchlid);
}
}
//---------------------------------------------------------------没有线索化前的遍历
/*void print(Tree *T)
{
if (T->date == NULL)
return;
else
{
print(T->lchild);
cout << T->date;
print(T->rchlid);
}
}
*/
//------------------------------------------------------------------
//二叉树线索化
void InTreeding(Tree *T)
{
if (T->data != '#')
{
InTreeding(T->lchild);//递归左子树线索化
//没有左孩子
//---------------------------------------------------------
if (T->lchild->data == '#')
{
T->lchild = pre;//左孩子指向前驱
T->LTag = Thread;//前驱线索
}
if (pre->rchlid->data == '#')//前驱没有右孩子
{
pre->RTal = Thread;//后继线索
pre->rchlid = T;//右孩子指向后继
}
pre = T;//保持pre指向T的前驱
//----------------------------------------------------------
InTreeding(T->rchlid);//递归右孩子线索化
}
}
//遍历
void InoderTree(Tree *T)
{
Tree *p;
p = T->lchild;//指向根结点
//当空树或遍历结束时p==T
while (p != T)
{
while (p->LTag == Link)//当p->LTag==Thread时到达第一个结点
p = p->lchild;
cout << p->data;
while (p->RTal == Thread&&p->rchlid != T)//存在后继且后继不指向头结点
{
p = p->rchlid;
cout << p->data;
}
p = p->rchlid;//指向它的右孩子
}
}
int main()
{
first = new Tree();
root = new Tree();
pre = first;//使得pre一开始指向头节结点,方便让第一个结点的左孩子指向头结点
first->lchild = root;//头结点的右孩子指向根点
CreateTree(root);
InTreeding(root);
first->rchlid->RTal = 1;
first->rchlid->rchlid = first;//让最后结点的右孩子也指向头结点
InoderTree(first);
return 0;
}