严蔚敏视频 笔记21
先序序列的规律:根结点为第一个元素
中序序列的规律:根结点在左子树和右子树的中间
根据先序和中序就可唯一确定一个二叉树
6.5 线索二叉树
线索二叉树:
遍历二叉树的结果是求得结点的一个线性序列
指向该线性序列中的“前驱”和“后继”的指针称作“线索”
包含“线索”的存储结构叫做“线索链表”
约定:
在二叉链表的结点中增加两个标志域,并作如下规定:
若左子树不空,则lchild域的指针指向其左子树,左标志域的值为0;否则lchild域的指针指向其“前驱”,且左标志域的值为1
若右子树不空,则rchild域的指针指向其右子树,右标志域的值为0;否则rchild域的指针指向其“后继”,且右标志域的值为1
线索链表的结构描述:
typedef enum{Link,Thread} PointerThr;
// Link==0, Thread==1
typedef struct BiThrNode {
TElemType data;
struct BiThrNode *lchild,*rchild; // 左右指针
PointerThr LTag,RTag; // 左右标志
} BiThrNode, *BiThrTree;
遍历算法
for(p=firstNode(T);p;p=Succ(p)) Visit(p);
关键:找第一个结点 找后继
中序线索化链表的遍历算法
Status InOrderTraverse_Thr(BiThrTree T,Status (*Visit)(TElemType e)) {
p=T->lchild; // p指向根结点
while(p!=T) { // 空树或遍历结束时,p==T
while(p->LTag==Link) p=p->lchild;
if(!Visit(p->data)) return ERROR;
while(p->RTag==Thread&&p->rchild!=T) {
p=p->rchild; Visit(p->data); // 访问后继结点
}
p=p->rchild; // p进至其右子树根
}
return OK;
}
中序使用起来最方便
如何建立线索链表
在中序遍历过程中修改结点的左右指针域,以保存当前访问结点的“前驱”和“后继”信息,遍历过程中附设指针pre,并始终保持指针pre指向当前访问的指针p所指结点的前驱
void InThreading(BiThrTree p) {
if(p) {
InThreading(p->lchild); // 左子树线索化
if(!p->lchild) {
p->LTag=Thread;
p->lchild=pre;
} // 建立前驱线索
if(!pre->rchild) {
pre->RTag=Thread;
pre->rchild=p;
} // 建立后继线索
pre=p;
InThreading(p->rchild); // 右子树线索化
}
}
Status InOrderThreading(BiThrTree &Thrt,BiThrTree T) {
if(!(Thrt=(BiThrTree)malloc(sizeof(BiThrNode)))) exit(OVERFLOW);
Thrt->LTag=Link;
Thrt->RTag=Thread;
Thrt->rchild=Thrt;
if(!T) Thrt->lchild=Thrt; // 添加头结点
else {
Thrt->lchild=T;
pre=Thrt;
InThreading(T);
pre->rchild=Thrt; // 子树线索化
pre->RTag=Thread;
Thrt->rchild=pre; // 处理最后一个结点
}
return OK;
}