由于含有n个结点的二叉树,有2n个指针域,然而只有n-1 个指针域被利用,还剩下 n+1 个指针域,是空闲的,而线索化正是利用这些空的指针域,
当这个结点没有左儿子时,我们让其左指针指向遍历的前一个元素,即其前驱元素,而当这个结点没有右儿子时,我们让其右指针指向其遍历的下一个元素,即后继元素,同时为了区分这个指针存放的是否为线索,设置标志位。
本文给出中序线索化的代码实现,在本文中仿照链表定义了一个头结点,在线索化完成后,我们让头结点左指针域指向树的根节点,其右指针域指向中序遍历的最后一个元素。
定义全局变量指针pre始终指向遍历结点的前一个遍历的结点
#include <iostream>
using namespace std;
struct Treenode
{
char val;
Treenode *left;
Treenode * right;
int Ltag; // 等于1 代表指针为线索, 等于 0 代表非线索
int Rtag;
Treenode(int x):val(x),left(nullptr),right(nullptr),Ltag(0),Rtag(0){}
Treenode():val(0),left(nullptr),right(nullptr),Ltag(0),Rtag(0){}
};
typedef struct Treenode TreeNode;
TreeNode *pre; //定义全局变量pre 用来作为线索化过程指向中遍历元素前一个元素的指针
void perCreate(TreeNode *&root) //前序创建二叉树 ,以引用传递指针
{
char value;
cin>>value;
if(value=='0')
{
root=nullptr;
}
else
{
root=new TreeNode;
root->val=value;
perCreate(root->left);
perCreate(root->right);
}
}
void inorderbrowse(TreeNode *root) //递归中序遍历
{
if(root==nullptr) return ;
inorderbrowse(root->left);
cout<<root->val<<" ";
inorderbrowse(root->right);
}
void Threading(TreeNode *root) //线索化过程
{
if(root!=nullptr)
{
Threading(root->left);
if(root->left==nullptr)
{
root->Ltag=1;
root->left=pre;
}
else root->Ltag=0;
if(pre->right==nullptr)
{
pre->Rtag=1;
pre->right=root;
}
else pre->Rtag=0;
pre=root;
Threading(root->right);
}
}
void InThreading(TreeNode *root,TreeNode *&head) //构建线索化二叉树,参数有头结点
{
head= new TreeNode ; //head为头结点
head->Rtag=1;
head->right=head; //将头结点其右指针初始化为自身
if(root == nullptr) //树根为空时,直接返回
return ;
head->left=root; //当整个树根非空时,使头结点的左儿子指向其根节点
pre=head;
Threading(root); //调用线索化函数
pre->Rtag=1; //线索化结束时pre指向中序遍历序列中的最后一个元素,将其右指针指向头结点,同时头结点右指针指向该最后一个结点
pre->right=head;
head->right=pre;
}
void InbrowseThread(TreeNode *head) //中序遍历线索化二叉树
{ //参数为头结点
TreeNode* p=head->left; //正如我们所说在线索化工作结束的二叉树中,头结点其左指针指向根节点(树非空的情况)
while(p!=head) //当为非空树时,或遍历未结束时
{
while(p->Ltag==0) p=p->left; //当左指针为非线索时,沿左指针移动,直到其左指针为线索
cout<<p->val<<" "; //左
while(p->Rtag==1&&p->right !=head)
{
p=p->right;
cout<<p->val<<" "; //中
}
p=p->right; //右
}
}
int main()
{
TreeNode *root1; //定义根节点
TreeNode *head; //定义头结点
perCreate(root1);
cout<<"中序遍历:";
inorderbrowse(root1);
cout<<endl<<" 线索化:";
InThreading(root1,head);
InbrowseThread(head);
return 0;
}