线索二叉树
对于节点个数为n的二叉树,采用二叉链存储结构时,每个节点有2个指针域,总共有2n个指针域,其中只有n-1个分支,所以有2n-(n-1),n+1个空指针。这些空指针不存储任何信息,白白浪费了内存空间。
在介绍树的链式存储结构的缺点时,我们提到:
寻找一个孩子节点的双亲是比较麻烦的,要用递归函数来遍历整棵树。
对于一棵经常需要遍历或查找节点的二叉树,如何提高操作的时间效率呢?既然有那么多空指针,我们可以在第一次遍历二叉树时把空指针利用起来,存放前驱节点和后继节点的地址。我们把指向前趋和后继节点的指针称为线索。
创建线索的过程称为线索化,一棵线索化的二叉树称为线索二叉树(Threader Binary Tree)。
同一棵二叉树用不同的遍历方法会产生不一样的线索二叉树
比如:
- 先序线索二叉树
- 中序线索二叉树
- 后序线索二叉树

线索二叉树节点
typedef struct _tbtnode{
ElemType data;
int ltag, rtag;
struct _tbtnode *lchild, *rchild;
}tbtnode;
为了区分线索和分支,在原有二叉树节点的基础上增加标记ltag和rtag。
| 0 | 1 | |
|---|---|---|
| ltag | 指向左孩子节点 | 指向遍历序列的后继节点 |
| rtag | 指向右孩子节点 | 指向遍历序列的前驱节点 |
建立线索二叉树
建立某种次序的线索二叉树
- 以该遍历方法遍历一棵二叉树
- 在遍历过程中,检查当前访问节点的左孩子指针、右孩子指针是否为空
- 如果左孩子指针为空,则改为指向前驱节点的线索
- 如果右孩子指针为空,则改为指向后继节点的线索
以中序线索二叉树为例,讨论建立线索二叉树的算法
对于中序遍历线索化的递归函数:
- p总是指向当前线索化的节点
- pre作为全局变量,指向刚刚访问过的节点
*pre是*p的中序前驱节点,*p是*pre的中序后继节点
btnode* pre; //全局变量
void
Thread(tbtnode* p)
{
if (p != NULL) {
Thread(p->lchild); //中序遍历先遍历左子树
if (p->lchild == NULL) {
p->ltag = 1; //设置线索标记
p->lchild = pre; //指向当前节点的前驱节点
}
else {
p->ltag = 0; //设置孩子指针标记
}
if (pre->rchild == NULL) {
pre->rtag = 1;
pre->rchild = p; //前一个节点指向当前节点,即让指针指向后继节点
}
else {
pre->rtag = 0;
}
pre = p; //pre和p向前移动
Thread(p->rchild); //中序遍历后遍历右子树
}
}

在遍历线索二叉树时我们发现,这棵树实际上可以看成是一个双向链表,和双链表一样,给线索二叉树增加头节点,这样一来我们既可以从第一个节点起沿着后继遍历,也可以从最后一个节点沿着前驱遍历。

tbtnode*
createThread(tbtnode* t)
{
tbtnode* root;
root = (tbtnode*)malloc(sizeof(tbtnode));
root->ltag = 0;
root->rtag = 1;
root->rchild = t; //头结点的右孩子指针开始时指向树的根节点
if (t == NULL) {
root->lchild = root;
}
else {
root->lchild = t;
pre = root;
Thread(t);
pre->rchild = root;
/*
* 离开Thread()时p为空指针, pre指向了中序遍历序列的最后一个节点
* 让最后一个节点的右孩子指针指向后继节点root
*/
pre->rtag = 1;
root->rchild = pre;
}
return root;
}
遍历线索二叉树
用非递归算法即可遍历线索二叉树,空间复杂度为O(1)
void
InOrderTraverse_Thr(tbtnode* t)
{
tbtnode* p = t->lchild; //p指向根节点
while (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; //p指向下一棵子树
}
}

浙公网安备 33010602011771号