在一棵具有n个节点二叉树中,若采用二叉链表存储结构,在2n个指针域中有n+1个空指针域,线索二叉树就是利用这些空指针来指向节点的前驱节点或后驱节点从而使二叉树的某些操做得到优化的目的,如何区别某个指针存放的究竟是指针还是线索呢?主要有以下两种方法:
- 每个节点新增两个标志位域lbit和rbit,有
p->lbit = 0 | p-> lchild 为指向前驱的线索 |
---|---|
p->lbit = 1 | p->lchild为指向左孩子的指针 |
- 不改变节点的构造,仅在作为线索的地址前面加一个负号,即负的地址表示线索,正的表示指针(不常用)
线索二叉树的构造:
定义二叉链表结构类型:
typedef struct node
{
Elemtype data;
struct node *lchild,*rchild;
int lbit,rbit;
}TBTNode,*TBTREE;
定义好节点之后,我们首先来建立一棵线索二叉树。这里以中序二叉树的线索化为例。
说明: prior指针指向当前访问节点的直接前驱节点,prior的初值为头结点的指针,HEAD初始值指向头结点,但在算法执行过程中,HEAD总是指向当前访问的节点。
void INTHREAD(TBTREE &HEAD)
{
TBTREE piror;
if(HEAD){
INTHREAD(HEAD->lchild);
if(HEAD->rchild == NULL){
HEAD->rbit = 0;
}
if(HEAD->lchild == NULL){
HEAD->lchild = piror;
HEAD->lbit = 0;
}
}
if(piror->rbit == 0){
piror->rchild = HEAD;
}
piror = HEAD;
INTHREAD(HEAD->rchild);
}
线索二叉树的利用:
1:在中序线索二叉树中确定地址为x的节点的直接前驱节点
分析:
- x->lbit = 0;x->lchild所指节点就是x的直接前驱节点。
- x->lbit = 1;说明x节点有左子树,它的直接前驱节点就是x节点左子树最右边的那个节点;即顺着x节点左子树的根的右指针链往下寻找直到某节点的rchild域是线索为止。代码如下:
TBTREE INPRIOR(TBTREE x)
{
TBTREE s;
s = x->lchild;
if(x->lchild)
while(s->rbit == 1)
s = s->rchild;
return s;
}
在中序线索二叉树中确定地址为x的节点的直接后驱节点
分析:
- x->rbit = 0; x->rchild所指节点就是x的直接后驱节点
- x->ribt = 1;沿着x节点的右子树的根的左指针链往下找,直到某节点的lchild域为线索为止。 代码如下:
TBTREE INSUCC(TBTREE x)
{
TBTREE s;
s = x->rchild;
if(s)
while(s->lbit == 1)
s = s->lchild;
return s;
}
利用线索二叉树遍历二叉树
TBTREE INSUCC(TBTREE x)
{
TBTREE s;
s = x->rchild;
if(s)
while(s->lbit == 1)
s = s->lchild;
return s;
}
线索二叉树的更新:
void INSERT_RIGHT(TBTREE s,TBTREE p)
{
TBTREE q;
p->rchild = s->rchild;
p->rbit = s->rbit;
p->lchild = s;
s->rchild = p;
s->rbit = 1;
if(p->rbit == 1){
q = INSUCC(P); //如果s原来的右子树非空时,找到s的直接继 节点w,将w改为p的直接后继节点,p改为w的直接前继节点
q->lchild = p;
}
}