数据结构16————二叉树的线索化
文章目录
一.内容
- 二叉树的线索化
- 线索二叉树的线索化
- 线索二叉树的简单应用
二.二叉树的线索化
1.二叉树的线索化的原因
当我们使用二叉链表实现二叉树,对空间会造成很大的浪费。当我们存储有n个节点的二叉树时,一共有2n个指针域,而二叉树一共有n-1个分支连线。即只有n-1个指针域指向节点,剩下的n+1都存的是空指针NULL。
为了提高空间的利用率,所以我们将原本存NULL的指针域存为其他有价值的信息(改节点的前驱和后继)
2.二叉树线索化的步骤
将原本存在存NULL的指针域存为该节点的前驱和后继。那么问题来了,前驱和后继指的是什么遍历序列的前驱和后继呢?答案是都可以,线索化分为3种,前序线索二叉树,中序线索二叉树,后序线索二叉树
我们以中序二叉树的线索化为例
- 画出二叉树,写出二叉树的中序序列
- 对于每个节点
- 如果左子树为空,左指针连向它的前驱节点
- 如果右子树为空,右指针连向它的后驱节点
三.二叉树的线索化的代码实现
1.二叉树的结构设置
如果沿用之前的的二叉链表来实现的二叉线索树,就会存在一个问题,没法判断这个指针域,是原来二叉树的连线,还是线索化后的连线。为了解决上面这个问题我们就要增加一个标志域,来表示该指针是不是线索化后的指向。
2.二叉树的结构体代码
typedef enum {Link,Thread} PointerTag;//Link== 0 表示指向左右孩子的节点。
//Therad == 1表示指向前驱或者后继
typedef char Elemtype;
typedef struct BithrNode{ //二叉线索节点结构
Elemtype data;
struct BithrNode *lchild,*rchild;//左右孩子指针
PointerTag LTag;
PointerTag RTag;
}BiThrNode,*BiThrTree;
3.二叉树线索化代码
可以很明显的看出二叉树的线索化,只是将中序遍历代码进行更改
void InThreading (BiThrTree root){
if(root==NULL)
return;
InThreading(root->lchild);//递归左子树的线索化
if(root->lchild==NULL){
root->LTag =Thread;
root->lchild = p; // 左孩子指向前驱
}
if(p!=NULL&&p->rchild == NULL){
p->RTag = Thread;
p->rchild = root;//前驱指向根节点
}
p = root; // 更新前驱
InThreading(root->rchild);//递归右子树的线索化
}
四.二叉线索化的应用
使用二叉线索树进行中序遍历
如果给定的二叉树中序线索树,要进行二叉树的中序遍历。就可以不使用二叉树中序遍历的代码,可以使用二叉中序线索树的特有遍历方法
思路:
- 找到二叉中序序列的第一个节点
- 根据节点的右子树指针和后驱指针来寻找下一个节点
- 当遍历的最后一个节点是,右指针域为NULL
void InOrderTraverse_Thr(BiThrTree root){
BiThrNode *p;
p=root->lchild;// p为根的左孩子
while(p!=NULL) // 空树或者遍历结束 p == T
{
while(p->LTag == Link) //找到中序序列的第一个节点
p = p ->lchild;
printf("%c",p->data);
while(p->RTag==Thread && p->rchild !=NULL){
p = p->rchild;
printf("%c",p->data);
}
p= p->rchild;
}
}
五.参考资料
《大话数据结构》
《数据结构与算法》