6.3线索二叉树(二叉树的线索化)
问题引入:以二叉链表作为存储结构时,只能得到结点的左、右孩子的信息,不能得到直接前驱、后继的信息。
问题解决:将二叉树线索化。
实现原理:n个结点的二叉树具有n+1个空指针域,利用这些空指针域存储结点的前驱、后继信息。
实质:线索化的实质是将二叉链表中的空指针改为指向前驱、后继的线索。
(1)二叉树的存储表示
enum {link,thread};//link=0; thread=1;
typedef struct bintree
{
char data;
struct bintree *lchild, *rchild;
int ltag,rtag;//标志域。指示 指针或线索
}BiNode, *BiTree;
见6.1二叉树的创建章节。
(3)中序线索化 及 遍历(注意注释内容)
BiTree inorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);//建立头指针
if(!thrt)
exit(0);
thrt->rtag = thread;//右指针回指
thrt->rchild = thrt;
thrt->ltag = link;
if(!t)//若二叉树空,左指针回指
thrt->lchild = thrt;
else
{
thrt->lchild = t;
pre = thrt;
in_threading(t);//中序遍历进行中序线索化
pre->rtag = thread;//最后一个节点线索化
pre->rchild = thrt;
thrt->rchild = pre;
}
return thrt;
}
void in_threading(BiTree p)
{
if(p)
{
in_threading(p -> lchild);//左子树线索化
if(! p->lchild)//前驱线索
{
p->ltag = thread;
p->lchild = pre;
}
if(! pre->rchild)//后继线索
{
pre->rtag = thread;
pre->rchild = p;
}
pre = p;//保持pre指向 p 的前驱
in_threading(p->rchild);//右子树线索化
}
}
void inorder_traverse(BiTree thrt)
{
BiTree p = thrt->lchild;
while(p != thrt)//空树或遍历结束时,p==thrt
{
while(p->ltag == link)
{
p = p->lchild;
}
printf("%c ",p->data);
if(p->rtag == thread && p->rchild != thrt)
{
p = p->rchild;
printf("%c ",p->data);
}
p = p->rchild;
}
}
BiTree preorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);
if(! thrt)
exit(0);
thrt -> rtag = thread;
thrt -> rchild = thrt;
thrt -> ltag = link;
if(!t)
thrt -> lchild = thrt;
else
{
thrt -> lchild = t;
pre = thrt;
pre_threading(t);
pre -> rtag = thread;
pre -> rchild = thrt;
thrt -> rchild = pre;
}
return thrt;
}
void pre_threading(BiTree p)
{
if(p)
{
if(! p->lchild)
{
p -> ltag = thread;
p -> lchild = pre;
}
if(!p -> rchild)
p -> rtag = thread;
if(pre && pre->rtag == thread)
pre -> rchild = p;
pre = p;
if(p->ltag == link)
pre_threading(p -> lchild);
if(p->rtag == link)
pre_threading(p -> rchild);
}
}
void preorder_traverse(BiTree thrt)
{
BiTree p = thrt -> lchild;
printf("%c ",p->data);
while(p->rchild != thrt)
{
if(p->ltag == link)
p = p->lchild;
else
p = p->rchild;
printf("%c ",p->data);
}
}
BiTree postorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);
if(! thrt)
exit(0);
thrt -> rtag = thread;
thrt -> rchild = thrt;
thrt -> ltag = link;
if(!t)
thrt -> lchild = thrt;
else
{
thrt -> lchild = t;
pre = thrt;
post_threading(t);
pre -> rtag = thread;
pre -> rchild = thrt;
thrt -> rchild = pre;
}
return thrt;
}
void post_threading(BiTree p)
{
if(p)
{
post_threading(p->lchild); //左子树线索化
post_threading(p->rchild); //右子树线索化
if(!p->lchild)
{
p->ltag=thread;
p->lchild=pre;
}
if(!pre->rchild)
{
pre->rtag=thread;
pre->rchild=p;
}
pre=p;
}
}
void postorder_traverse(BiTree thrt)
{
BiTree p = thrt;
while(p->ltag==link||p->rtag==link) //有左孩子先访问左孩子,没有左孩子先访问右孩子
{
while(p->ltag==link)
p=p->lchild;
if(p->rtag==link) //访问左孩子为空的结点的右孩子
p=p->rchild;
}
printf("%c ",p->data);
while(p!=T) //p不为根结点
{
if(p->rtag==link) //若p是有兄弟的左孩子
{
if(pre->rtag==thread||p==pre->rchild) //若p是双亲的右孩子或是独生左孩子,则后继为双亲
p=pre;
else
{
p=pre->rchild; //后继为双亲的右子树上按照后序遍历访问的第一个结点。
while(p->ltag==link||p->rtag==link)
{
while(p->ltag==link)
p=p->lchild;
if(p->rtag==link)
p=p->rchild;
}
}
}
else
p=p->rchild; //p指向后继
printf("%c ",p->data);
}
}
/* 样例输入: abc##de#g##f### */
# include <stdio.h>
# include <stdlib.h>
# define len (sizeof(BiNode))
# define OK 1
enum {link,thread};
typedef struct bintree
{
char data;
struct bintree *lchild, *rchild;
int ltag,rtag;
}BiNode, *BiTree;
BiTree T, thrt, pre;
int bintree_creat(BiTree *q);
void welcome(BiTree t);
BiTree preorder_threading(BiTree thrt,BiTree t);//先序
void pre_threading(BiTree p);
void preorder_traverse(BiTree thrt);
BiTree inorder_threading(BiTree thrt,BiTree t);//中序
void in_threading(BiTree p);
void inorder_traverse(BiTree thrt);
BiTree postorder_threading(BiTree thrt,BiTree t);//后序
void post_threading(BiTree p);
void postorder_traverse(BiTree thrt);
int main()
{
printf("now create the bintree first,please input :\n");
bintree_creat(&T);
welcome(T);
return 0;
}
int bintree_creat(BiTree *q)
{
char ch;
ch=getchar();
if(ch=='#')
(*q)=NULL;
else
{
(*q) = (BiTree )malloc(len);
if((*q))
{
(*q)->data = ch;
(*q)->ltag = link;
(*q)->rtag = link;
bintree_creat(&(*q) -> lchild);
bintree_creat(&(*q) -> rchild);
}
}
return OK;
}
void welcome(BiTree t)
{
int i;
printf("input 1 :preorder_threading the bintree .\n");
printf("input 2 :inorder_threading the bintree .\n");
printf("input 3 :postorder_threading the bintree .\n\n");
scanf("%d",&i);
switch (i)
{
case 1 :thrt = preorder_threading(thrt,t);
preorder_traverse(thrt);
printf("\n\n"); break;
case 2 :thrt = inorder_threading(thrt,t);
inorder_traverse(thrt);
printf("\n\n"); break;
case 3 :thrt = postorder_threading(thrt,t);
postorder_traverse(thrt);
printf("\n\n"); break;
default :printf("input error !");
exit(1);
}
}
BiTree preorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);
if(! thrt)
exit(0);
thrt -> rtag = thread;
thrt -> rchild = thrt;
thrt -> ltag = link;
if(!t)
thrt -> lchild = thrt;
else
{
thrt -> lchild = t;
pre = thrt;
pre_threading(t);
pre -> rtag = thread;
pre -> rchild = thrt;
thrt -> rchild = pre;
}
return thrt;
}
void pre_threading(BiTree p)
{
if(p)
{
if(! p->lchild)
{
p -> ltag = thread;
p -> lchild = pre;
}
if(!p -> rchild)
p -> rtag = thread;
if(pre && pre->rtag == thread)
pre -> rchild = p;
pre = p;
if(p->ltag == link)
pre_threading(p -> lchild);
if(p->rtag == link)
pre_threading(p -> rchild);
}
}
void preorder_traverse(BiTree thrt)
{
BiTree p = thrt -> lchild;
printf("%c ",p->data);
while(p->rchild != thrt)
{
if(p->ltag == link)
p = p->lchild;
else
p = p->rchild;
printf("%c ",p->data);
}
}
BiTree inorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);//建立头指针
if(!thrt)
exit(0);
thrt->rtag = thread;//右指针回指
thrt->rchild = thrt;
thrt->ltag = link;
if(!t)//若二叉树空,左指针回指
thrt->lchild = thrt;
else
{
thrt->lchild = t;
pre = thrt;
in_threading(t);//中序遍历进行中序线索化
pre->rtag = thread;//最后一个节点线索化
pre->rchild = thrt;
thrt->rchild = pre;
}
return thrt;
}
void in_threading(BiTree p)
{
if(p)
{
in_threading(p -> lchild);//左子树线索化
if(! p->lchild)//前驱线索
{
p->ltag = thread;
p->lchild = pre;
}
if(! pre->rchild)//后继线索
{
pre->rtag = thread;
pre->rchild = p;
}
pre = p;//保持pre指向 p 的前驱
in_threading(p->rchild);//右子树线索化
}
}
void inorder_traverse(BiTree thrt)
{
BiTree p = thrt->lchild;
while(p != thrt)//空树或遍历结束时,p==thrt
{
while(p->ltag == link)
{
p = p->lchild;
}
printf("%c ",p->data);
if(p->rtag == thread && p->rchild != thrt)
{
p = p->rchild;
printf("%c ",p->data);
}
p = p->rchild;
}
}
BiTree postorder_threading(BiTree thrt,BiTree t)
{
thrt = (BiTree )malloc(len);
if(! thrt)
exit(0);
thrt -> rtag = thread;
thrt -> rchild = thrt;
thrt -> ltag = link;
if(!t)
thrt -> lchild = thrt;
else
{
thrt -> lchild = t;
pre = thrt;
post_threading(t);
pre -> rtag = thread;
pre -> rchild = thrt;
thrt -> rchild = pre;
}
return thrt;
}
void post_threading(BiTree p)
{
if(p)
{
post_threading(p->lchild); //左子树线索化
post_threading(p->rchild); //右子树线索化
if(!p->lchild)
{
p->ltag=thread;
p->lchild=pre;
}
if(!pre->rchild)
{
pre->rtag=thread;
pre->rchild=p;
}
pre=p;
}
}
void postorder_traverse(BiTree thrt)
{
BiTree p = thrt;
while(p->ltag==link||p->rtag==link) //有左孩子先访问左孩子,没有左孩子先访问右孩子
{
while(p->ltag==link)
p=p->lchild;
if(p->rtag==link) //访问左孩子为空的结点的右孩子
p=p->rchild;
}
printf("%c ",p->data);
while(p!=T) //p不为根结点
{
if(p->rtag==link) //若p是有兄弟的左孩子
{
if(pre->rtag==thread||p==pre->rchild) //若p是双亲的右孩子或是独生左孩子,则后继为双亲
p=pre;
else
{
p=pre->rchild; //后继为双亲的右子树上按照后序遍历访问的第一个结点。
while(p->ltag==link||p->rtag==link)
{
while(p->ltag==link)
p=p->lchild;
if(p->rtag==link)
p=p->rchild;
}
}
}
else
p=p->rchild; //p指向后继
printf("%c ",p->data);
}
}
(7)撰写匆忙,表述简陋,必有疏漏。欢迎朋友们批评指正。
2014/10/21