//线索二叉树
#include<stdio.h>
#include<stdlib.h>
typedef struct ThreadNode{
int data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag; //tag=0时,指向左子树或又子树,tag为1时,指向中序遍历序列的前驱或后继
}ThreadNode,*ThreadTree;
ThreadNode *pre=NULL; //定义全局变量pre,指向当前访问结点的前驱
ThreadTree CreateThreadTree(ThreadTree T, bool isRoot){//创建一个二叉树 #代表空节点
char ch;
if (isRoot)
printf("Root: ");
fflush(stdin);
scanf("%c", &ch);
fflush(stdin);
if (ch != '#'){
isRoot = false;
T = new ThreadNode;
T->data = ch;
T->lchild = NULL;
T->rchild = NULL;
printf("%c's left child is: ", T->data);
T->lchild = CreateThreadTree(T->lchild, isRoot);
printf("%c's right child is: ", T->data);
T->rchild = CreateThreadTree(T->rchild, isRoot);
}
return T;
}
void visit(ThreadNode *q){
if(q->lchild == NULL){//左子树为空 建立前驱检索
q->lchild=pre;
q->ltag=1;
}
if(pre!=NULL && pre->rchild==NULL){
pre->rchild=q; //使前驱结点的后继线索指向当前结点
pre->rtag=1;
}
pre=q;
}
void InThread(ThreadTree T){//中序边遍历边线索化
if(T!=NULL){
InThread(T->lchild);
visit(T);
InThread(T->rchild);
}
}
void CreateInThread(ThreadTree T){//中序线索化二叉树T
pre=NULL;
if(T!=NULL){
InThread(T);
pre->rtag=1; //处理遍历的最后一个结点,此时pre->rchild=NULL
}
}
void PreThread(ThreadTree T){//先序 边遍历边线索化
if(T!=NULL) {
visit(T); //先处理根节点
if(T->ltag==0){ //lchild不是前驱线索
PreThread(T->lchild);
}
PreThread(T->rchild);
}
}
void CreatePreThread(ThreadTree T){//先序线索化二叉树T
pre=NULL;
if(T!=NULL){
PreThread(T);
pre->rtag=1; //处理遍历的最后一个结点,此时pre->rchild=NULL
}
}
void PostThread(ThreadTree T){//后序 边遍历边线索化
if(T!=NULL) {
PreThread(T->lchild);
PreThread(T->rchild);
visit(T); //后处理根节点
}
}
void CreatePostThread(ThreadTree T){//先序线索化二叉树T
pre=NULL;
if(T!=NULL){
PreThread(T);
pre->rtag=1; //处理遍历的最后一个结点,此时pre->rchild=NULL
}
}
int main(){
ThreadTree T;
T = CreateThreadTree(T , true);
CreateInThread(T);
return 0;
}
后序遍历的线索化有一个问题:当根节点的右孩子的rchild不为空时,由于后序线索二叉树为 左、右、根 ,即一个有子结点的结点的后继为双亲节点,而此结点因为有右孩子,rchild指向右孩子无法指向其双亲节点,因此后序线索二叉树中有左儿子和右儿子的点的lchild、rchild指向的是左儿子与右儿子(都是前驱),因此无法求后继(前序无法求前驱同理)。
因此当根结点T的右孩子W的rchild!=NULL时,根节点T无法被遍历(即W->rchild已被用,无法得到W的后继T)。 (可用栈解决此问题)