线索二叉树的介绍
线索二叉树是由二叉树的基础上进行了改良,改良后比起二叉树增加了线索 ,使得遍历二叉树时不用回溯直接到下一节点。
一、线索二叉树的优缺点
优点:
可以快速的遍历二叉树,不需要回溯,所以可以节约很多空间和时间。
可以方便的找到二叉树的前驱和后继节点,不需要遍历整个二叉树。
线索二叉树可以用于解决一些特定的问题,如寻找二叉树中的的某个节点。
缺点:
线索二叉树树的构建比起二叉树更复杂,需要额外的空间来存储线索。
删除和插入操作比较麻烦,要操作完后更新线索。
所以线索二叉树比较合适遍历比起二叉树,可能其他操作可能还不如二叉树。
总得来说,线索二叉树在遍历二叉树上有一定的优势,但是在其他的方面可能还不如普通二叉树。
所以在使用二叉树时需要根据具体情况来选择是否使用。如果要经常遍历二叉树,可以使用线索二叉树。如果经常进行插入删除操作可以使用普通二叉树。
二、线索二叉树的基本概念和实现
遍历二叉树是以一定的规则将二叉树中的结点排列成一个线性序列,得到二叉树中结点的先序序列,中序序列或后序序列。这实质上是对一个非线性结构进行线性化操作,使每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个直接前驱和直接后驱(在不至于混淆和情况,后续 描述中省去“直接”二字)。
--------------------数据结构课本
线索二叉树实现具体描述
线索二叉树是一种特殊的二叉树,所以先要构建一个二叉树,然后在二叉树的基础上增加线索,使得遍历二叉树时不用进行回溯,直接转到下一个结点。线索二叉树包括前序线索二叉树,中序线索二叉树和后序线索二叉树,它们实现的方式有点点区别。
以下是线索二叉树的实现描述:
定义线索二叉树的结点结构体,包含了结点的值,左右指针和线索标志。线索标志用于标记结点的左右指针是指向子节点还是前驱或后继结点。
结构体代码如下:
typedef struct BiThrNode
{
TElemType data;
struct BiThrNode *lchild,*rchild;//左右孩子指针
int LTag,RTag;//左右标志
}BiThrNode,*BiThrTree;
定义一个全局变量,用于保存中序遍历的前驱结点
BiThrTree pre;
构建二叉树
void createtree(BiThrTree t)
{
char c;
scanf("%c",&c);
getchar();
if(c=='#')//二叉树以#号结束
t=NULL;
else
{
t=(BiThrNode *)malloc(sizeof(BiThrNode));//构建结点空间
t->data=c; //给结点赋值
createtree(t->lchild);//建立左结点
createtree(t->rchild);//建立右结点
}
}
然后定义一个函数,用来构造线索二叉树
void createTree(BiThrTree p)
{
if(p){
createTree(p->lchild); //左子树递归线索化
if(!p->lchild){ //p的左孩子为空
p->LTag=1; //给p加上左线索
p->lchild=pre; //p的左孩子指针指向pre(前驱)
}
else p->LTag=0;
if(!pre->rchild){ //pre的右孩子为空
pre->RTag=1; //给pre加上右线索
pre->rchild=p; //pre的右孩子指针指向p(后继)
}
else pre->RTag=0;
pre=p; //pre指向前驱结点
createTree(p->rchild); //右子树递归线索化
}
}
遍历线索二叉树
void InOrderTraverse(BiThrTree t)
{
BiThrTree p;
p=t->lchild; //p指向根节点
while(p!=t){ //空树遍历结束时,p==t
while(p->LTag==0) //沿着左孩子一直向下
p=p->lchild;
printf("%c",p->data); //访问左子树为空的结点
while(p->RTag==1&&p->rchild!=t){//沿着右线索遍历
p=p->rchild;
printf("%c",p->data);
}
p=p->rchild; //转到右子树
}
}
以上是线索二叉树的主要步骤
三、综合代码
#include<stdio.h>
#include<stdlib.h>
#define TElemType char
typedef struct BiThrNode
{
TElemType data;
struct BiThrNode *lchild,*rchild;
int LTag,RTag;
}BiThrNode,*BiThrTree;
BiThrTree pre;
void createtree(BiThrTree t)
{
char c;
scanf("%c",&c);
getchar();
if(c=='#')//二叉树以#号结束
t=NULL;
else
{
t=(BiThrNode *)malloc(sizeof(BiThrNode));//构建结点空间
t->data=c; //给结点赋值
createtree(t->lchild);//建立左结点
createtree(t->rchild);//建立右结点
}
}
void createTree(BiThrTree p)
{
if(p){
createTree(p->lchild); //左子树递归线索化
if(!p->lchild){ //p的左孩子为空
p->LTag=1; //给p加上左线索
p->lchild=pre; //p的左孩子指针指向pre(前驱)
}
else p->LTag=0;
if(!pre->rchild){ //pre的右孩子为空
pre->RTag=1; //给pre加上右线索
pre->rchild=p; //pre的右孩子指针指向p(后继)
}
else pre->RTag=0;
pre=p; //pre指向前驱结点
createTree(p->rchild); //右子树递归线索化
}
}
void InOrderTraverse(BiThrTree t)
{
BiThrTree p;
p=t->lchild; //p指向根节点
while(p!=t){ //空树遍历结束时,p==t
while(p->LTag==0) //沿着左孩子一直向下
p=p->lchild;
printf("%c",p->data); //访问左子树为空的结点
while(p->RTag==1&&p->rchild!=t){//沿着右线索遍历
p=p->rchild;
printf("%c",p->data);
}
p=p->rchild; //转到右子树
}
}
int main()
{
BiThrNode t;
createtree(&t);
createTree(&t);
InOrderTraverse(&t);
}