线索二叉树的建立与遍历C/C++
一、线索二叉树的定义
在采用二叉树链表做存储结构时,二叉树中的所有节点共有n+1个空指针域。因此可以利用二叉树的二叉树链表存储结构中的那些空指针域来指示节点在某种遍历序列中直接前驱和直接后继的位置信息。这些指向直接前驱节点和直接后继节点的指针被称为线索,加了线索的二叉树成为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化。
二、线索二叉树的结构
1、为每个节点增设两个标志位域ltag和rtag,令:
ltag = 0 //lchild指向节点的左孩子
ltag = 1 //lchild指向节点的前驱节点
rtag = 0 //rchild指向节点的右孩子
rtag = 1 //rchild指向节点的后继节点
定义线索二叉树的数据结构:
/*
*定义线索二叉树的数据结构
*/
typedef char elemtype ;
typedef struct BiThrNode
{
elemtype data ;
struct BiThrNode *lchild , *rchild ; //定义指向左右孩子的指针
unsigned ltag : 1 ;
unsigned rtag : 1 ; //定义是否是前驱后后续节点
} BiThrNodeType , *BiThrTree ;
BiThrTree pre ; //定义一个全局变量指向线索二叉树的前驱节点
三、建立线索二叉树
1、二叉树的线索化,实质上就是遍历一棵二叉树,在遍历过程中,访问节点的操作是检查当前结点的左右指针域是否为空,如果为空,即将他们改为前驱节点或后继节点的线索。为记录前驱节点,定义pre为全局变量,始终指向当前结点的前驱节点。
下面为建立中序线索二叉树的递归算法:
BiThrTree pre ; //定义一个全局变量指向线索二叉树的前驱节点
/*
*中序遍历进行线索化
*/
void InThreading(BiThrTree p)
{
if(p)
{
InThreading(p->lchild) ; //将左孩子线索化
if(!p->lchild)
{
p->ltag = 1 ;
p->lchild = pre ;
}
if(!pre->rchild)
{
pre->rtag = 1 ;
pre->rchild = p ;
}
pre = p ;
InThreading(p->rchild) ; //将右孩子线索化
}
}
/*
*建立头节点,二叉树线索化
*/
int InOrderThr(BiThrTree *head , BiThrTree T)
{
if(!((*head) = (BiThrTree)malloc(sizeof(BiThrNodeType))))
{
return 0 ;
}
(*head)->ltag = 0 ;
(*head)->rtag = 1 ;
(*head)->rchild = (*head) ; //头指针回指
if(!T)
{
(*head)->lchild = *head ;
}
else
{
(*head)->lchild = T ;
pre = (*head) ;
InThreading(T) ;
pre->rchild = *head ;
pre->rtag = 1 ;
(*head)->rchild = pre ; //将最后一个节点线索化
}
return 1 ;
}
四、在中序线索二叉树上查找任意节点的中序前驱节点
对于中序线索二叉树上的任意节点,寻找其中序的前驱节点,有以下两种情况:
1、如果该节点的左标志域为1,那么其左指针所指向的节点便是它的前驱节点。
2、如果该节点的左标志为0,表明该节点有左孩子,根据中序遍历的定义,它的前驱节点是以该节点的左孩子为根节点的子树的最右节点,即沿着其左子树的右指针链向下查找,当某节点的右标志域为1时,它就是所要找的前驱节点。
算法如下:
/*
*在中序二叉树上寻找任意节点的前驱节点
*/
BiThrTree InPreNode(BiThrTree p)
{
BiThrTree pre ;
pre = p->lchild ;
if(p->ltag != 1)
{
while(pre->rtag == 0)
{
pre = pre->rchild ;
}
}
return pre ;
}
五、在中序线索二叉树上查找任意节点的中序后继节点
对于中序线索二叉树上的任意节点,寻找其中序的后继节点,有以下两种情况:
1、如果该节点的右标志域为1,那么其右指针所指向的节点便是它的后继节点。
2、如果该节点的右标志为0,表明该节点有右孩子,根据中序遍历的定义,它的后继节点是以该节点的右孩子为根节点的子树的最左节点,即沿着其右子树的左指针链向下查找,当某节点的左标志域为1时,它就是所要找的后继节点。
算法如下:
/*
*在中序二叉树上寻找任意节点的后继节点
*/
BiThrTree InPostNode(BiThrTree p)
{
BiThrTree post ;
post = p->rchild ;
if(p->rtag != 1)
{
while(post->rtag == 0)
{
post = post->lchild ;
}
}
return post ;
}
六、通过前驱节点与后继节点进行线索二叉树的遍历
1、从最后一个节点开始访问:
/*
*根据前驱节点进行中序线索二叉树的遍历
*/
void InOrderPre(BiThrTree head)
{
BiThrTree p ;
p = head->rchild ; //指向最后一个节点
while(p != NULL && p != head)
{
printf("%c " , p->data) ;
p = InPreNode(p) ;
}
}
2、从第一个节点开始遍历:
/*
*根据后继节点进行中序线索二叉树的遍历
*/
void InOrderPost(BiThrTree head)
{
BiThrTree p ;
p = head->lchild ;
while(p->ltag != 1)
{
p = p->lchild ;
}
while(p != NULL && p != head)
{
printf("%c " , p->data) ;
p = InPostNode(p) ;
}
}
七、测试的全部代码
/*
*建立线索二叉树,并测试一般性操作
*/
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAXSIZE 100
/*
*定义线索二叉树的数据结构
*/
typedef char elemtype ;
typedef struct BiThrNode
{
elemtype data ;
struct BiThrNode *lchild , *rchild ; //定义指向左右孩子的指针
unsigned ltag : 1 ;
unsigned rtag : 1 ; //定义是否是前驱后后续节点
} BiThrNodeType , *BiThrTree ;
BiThrTree pre ; //定义一个全局变量指向线索二叉树的前驱节点
/*
*中序遍历进行线索化
*/
void InThreading(BiThrTree p)
{
if(p)
{
InThreading(p->lchild) ; //将左孩子线索化
if(!p->lchild)
{
p->ltag = 1 ;
p->lchild = pre ;
}
if(!pre->rchild)
{
pre->rtag = 1 ;
pre->rchild = p ;
}
pre = p ;
InThreading(p->rchild) ; //将右孩子线索化
}
}
/*
*建立头节点,二叉树线索化
*/
int InOrderThr(BiThrTree *head , BiThrTree T)
{
if(!((*head) = (BiThrTree)malloc(sizeof(BiThrNodeType))))
{
return 0 ;
}
(*head)->ltag = 0 ;
(*head)->rtag = 1 ;
(*head)->rchild = (*head) ; //头指针回指
if(!T)
{
(*head)->lchild = *head ;
}
else
{
(*head)->lchild = T ;
pre = (*head) ;
InThreading(T) ;
pre->rchild = *head ;
pre->rtag = 1 ;
(*head)->rchild = pre ; //将最后一个节点线索化
}
return 1 ;
}
/*
*在中序二叉树上寻找任意节点的前驱节点
*/
BiThrTree InPreNode(BiThrTree p)
{
BiThrTree pre ;
pre = p->lchild ;
if(p->ltag != 1)
{
while(pre->rtag == 0)
{
pre = pre->rchild ;
}
}
return pre ;
}
/*
*在中序二叉树上寻找任意节点的后继节点
*/
BiThrTree InPostNode(BiThrTree p)
{
BiThrTree post ;
post = p->rchild ;
if(p->rtag != 1)
{
while(post->rtag == 0)
{
post = post->lchild ;
}
}
return post ;
}
void PreInO(char preOrder[] , char inOrder[] , int i , int j , int k , int h , BiThrTree *bt)
{
int m ;
if(!((*bt) = (BiThrTree)malloc(sizeof(BiThrNodeType))))
{
return ;
}
else
{
(*bt)->data = preOrder[i] ;
m = k ;
while(preOrder[i] != inOrder[m])
{
m++ ;
}
if(m == k)
{
(*bt)->lchild = NULL ;
}
else
{
PreInO(preOrder , inOrder , i + 1 , m - k + i , k , m - 1 , &((*bt)->lchild)) ; //进行左子树的建立
}
if(m == h)
{
(*bt)->rchild = NULL ;
}
else
{
PreInO(preOrder , inOrder , m - k + i + 1 , j , m + 1 , h , &((*bt)->rchild)) ; //进行右子树的建立
}
}
}
/*
*根据二叉树的前序遍历序列和中序遍历确定唯一二叉树
*根据二叉树的中序遍历和后续遍历不能确定唯一二叉树
*/
void ReBiTree(char preOrder[] , char inOrder[] , BiThrTree *bt)
{
int len ;
len = strlen(preOrder) ;
if(len <= 0)
{
return ;
}
else
{
PreInO(preOrder , inOrder , 0 , len - 1 , 0 , len - 1 , bt) ;
}
}
/*
*根据前驱节点进行中序线索二叉树的遍历
*/
void InOrderPre(BiThrTree head)
{
BiThrTree p ;
p = head->rchild ; //指向最后一个节点
while(p != NULL && p != head)
{
printf("%c " , p->data) ;
p = InPreNode(p) ;
}
}
/*
*根据后继节点进行中序线索二叉树的遍历
*/
void InOrderPost(BiThrTree head)
{
BiThrTree p ;
p = head->lchild ;
while(p->ltag != 1)
{
p = p->lchild ;
}
while(p != NULL && p != head)
{
printf("%c " , p->data) ;
p = InPostNode(p) ;
}
}
/*
*进行线索二叉树的测试
*/
void main()
{
BiThrTree head , T ;
char pre[MAXSIZE] , inOrder[MAXSIZE] ;
scanf("%s" , pre) ;
scanf("%s" , inOrder) ;
ReBiTree(pre , inOrder , &T) ; //建立普通二叉树
InOrderThr(&head , T) ; //建立头节点,并将二叉树线索化
InOrderPre(head) ;
printf("\n") ;
InOrderPost(head) ;
}

浙公网安备 33010602011771号