线索二叉树是为了便于访问一个结点的前驱和后继的信息。它在每个结点上新增了两个标志位,用来判断当前结点到底有没有左子树/右子树,如果没有,就把其利用起来存前驱/后继的信息。同时它也新增了一个头节点用来将整个二叉树联系起来。具体实现如下,有大量注释便于理解。
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
#include <malloc.h>
#include <stdlib.h>
typedef struct node
{
struct node *lchild;
struct node *rchild;
int lcFlag, rcFlag; //用来标记左子树和右子树是不是空的
char data;
}Node, *BinTree;
BinTree pre = NULL;
void Create(BinTree &root) //创建二叉树(本来指针是不用使用"&"引用符的,但是当指针为NULL时,函数传进来的也是指针的一个拷贝,而不是地址,具体解释看我之前的博客C语言指针传参问题)
{
char ch;
scanf("%c", &ch);
getchar();
if(ch == ' ')
root = NULL;
else
{
if(!(root = (BinTree)malloc(sizeof(Node))))
exit(0);
else
{
root->data = ch;
root->lcFlag = 0;
root->rcFlag = 0;
Create(root->lchild);
Create(root->rchild);
}
}
}
void InThreading(BinTree p) //构造中序线索二叉树
{
if(p)
{
InThreading(p->lchild); //递归找到最左边的结点
if(!p->lchild) //如果左子树为空,那就将这个空链域用来存前驱
{
p->lcFlag = 1; //标志位设为1,证明这是存的前驱地址而不是左子树
p->lchild = pre; //本来该存左子树的位置指向前驱节点
}
if(!pre->rchild) //如果前一个访问的结点的右子树为空,那用来存后继
{
pre->rcFlag = 1; //标志位设为1,存放后继地址
pre->rchild = p; //指向后继结点
}
pre = p; //更新上一个访问的结点
InThreading(p->rchild); //线索化右子树
}
}
int InOrderThreading(BinTree &head, BinTree root)
{
if(!(head = (BinTree)malloc(sizeof(Node))))
exit(0);
head->lcFlag = 0; //将头节点的左标志位设为0,把根结点设成它的左子树
head->rcFlag = 1; //右标志位拿来存中序遍历最后一个结点的地址,作为头节点的后继
head->rchild = head; //起初头节点的右结点自己指向自己
if(!root) //根结点为空时,指向自己
head->lchild = head;
else
{
head->lchild = root; //将根结点设为头节点的左子树
pre = head; //更新上一个访问的结点
InThreading(root); //二叉树线索化
pre->rchild = head; //把最后一个结点的右子树的后继存成头节点(形成了一个循环)
pre->rcFlag = 1;
head->rchild = pre; //头节点的后继设置成最后一个结点
}
return 1;
}
int InOrder(BinTree head) //中序遍历线索二叉树
{
BinTree p = head->lchild; //将p指向根结点
while(p != head) //由于线索化的时候把最后一个结点的后继设成了根结点,所以只要p!=head,就证明还没遍历完
{
while(p->lcFlag == 0) p = p->lchild; //中序遍历的特点,来到最左端
cout<<p->data<<" "; //输出对应的值
while(p->rcFlag == 1 && p->rchild != head) //如果右子树是个线索并且还有结点未访问
{
p = p->rchild; //直接来到后继并输出
cout<<p->data<<" ";
}
p = p->rchild; //来到p的右子树,继续以上过程
}
return 1;
}
int main()
{
BinTree head = NULL, root = NULL;
Create(root);
InOrderThreading(head, root);
InOrder(head);
return 0;
}