线索二叉树

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

指向该线性序列中的“前驱”和 “后继” 的指针 指针,称作“线索” 线索” 指针 线索
A B C D E F G H K
^B
C^ E^
^D^
包含 “线索” 的存储 结构,称作 “线索链 线索链 表” 与其相应的二叉树, 线索二叉树” 称作 “线索二叉树 线索二叉树
中序线索二叉树
A
0 1
BFra Baidu bibliotek
C
NULL
若该结点的右子树不空, 则rchild域的指针指向其右子树, 且右标志域的值为 “指针 Link=0”; 否则,rchild域的指针指向其“后继”, 且右标志的值为“线索 Thread=1”。 如此定义的二叉树的存储结构称作 “线索链表”。 线索链表”
线索链表的类型描述:
typedef enum { Link, Thread } PointerThr; // Link==0:指针,Thread==1:线索
由于在线索链表中添加了遍历中 得到的“前驱” 后继” 得到的“前驱”和“后继”的信 从而简化了遍历的算法。 息,从而简化了遍历的算法。
例如: 例如 对中序线索化链表的遍历算法 ※ 中序遍历的第一个结点 ?
左子树上处于“最左下”(没有左子树) “最左下” 的结点。
※ 在中序线索化链表中结点的后继 ?
void InThreading(BiThrTree p) { if ( p ) { InThreading ( p -> lchild ); //左子树中序线索化 左子树中序线索化 if ( p->lchild = = NULL ) { p->LTag=Thread; p->lchild= pre; } //左线索为 ; 左线索为pre 左线索为 if ( pre->rchild == NULL ) { pre->RTag=Thread; pre->rchild= p ;} //后继线索 后继线索 pre = p; //保持 指向 的前驱 保持pre指向 保持 指向p的前驱 InThreading(p -> rchild ); //右子树中序线索化 右子树中序线索化 } }//InThreading
} // InOrder
三、如何建立线索链表? 如何建立线索链表?
方法: 方法:在遍历过程中 修改空指针 例:画出下面二叉树 画出下面二叉树 的中序线索二叉树 B NULL D E F A NULL C
G
H
中序遍历序列: 中序遍历序列:D B E G A F H C
中序线索化二叉树
BiThrTree pre = NULL ;//设置前驱 设置前驱
后序线索树上找前驱和后继
找前驱: 找前驱: 若结点有右孩子,则右孩子是其前驱; 若结点有右孩子,则右孩子是其前驱; 否则,lchild指向其前驱。 否则, 指向其前驱。 指向其前驱
找后继: 找后继: 困难,需要知道其双亲。 困难,需要知道其双亲。
Status InOrderThreading (BiThrTree &Thrt , BiThrTree T ) { //将二叉树 改变为其中序线索二叉树 将二叉树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 ; InTreading( T ); //中序遍历进行中序线索化 中序遍历进行中序线索化 pre-> rchild = Thrt; pre->RTag= Thread; Thrt -> rchild = pre; } return OK; }
6.3 线索二叉树

何谓线索二叉树? 何谓线索二叉树? 线索链表的遍历算法 如何建立线索链表? 如何建立线索链表?
• •
一、何谓线索二叉树? 何谓线索二叉树?
遍历二叉树的结果是,求得结点的一线性 序列,对非线性结构进行线性化操作。 A B C D H G K 例如: 先序序列: 先序 ABCDEFGHK E 中序序列: 中序 F BD CAH G KFE 后序序列: 后序 DCBHKGFEA
前序线索树上找前驱和后继
找前驱: 找前驱: 困难
找后继: 找后继: 若结点有左孩子, 若结点有左孩子,则左孩子是后 否则, 指向后继。 继;否则,rchild指向后继。 指向后继
中序线索树上找前驱和后继
找前驱: 找前驱: 若左标记为1, 指向其前驱; 若左标记为 ,则lchild指向其前驱;否则, 指向其前驱 否则, 其前驱是其左子树上按中序遍历的最后一个结 点。 找后继: 找后继: 若右标记为1, 指向其后继; 若右标记为 ,则rchild指向其后继;否则, 指向其后继 否则, 其后继是其右子树上按中序遍历的第一个结点。 其后继是其右子树上按中序遍历的第一个结点。 中序的前驱和后继都往上指向祖先
A 0 A 0 F 0 B 0
NULL
D
E
1 C 0
NULL
1 D 1
1 E 1
1 F 1
对线索链表中结点的约定: 线索链表中结点的约定: 中结点的约定 在二叉链表的结点中增加两个标志域 增加两个标志域, 增加两个标志域 并作如下规定: 若该结点的左子树不空, 则Lchild域的指针指向其左子树, 且左标志域的值为“指针 Link=0”; 否则,Lchild域的指针指向其“前驱” 且左标志的值为“线索 Thread=1” 。
若无右子树,则为后继线索所指结点; 则为后继线索 则为后继线索 否则为对其右子树 右子树进行中序遍历 遍历时 否则为 右子树 遍历 访问的第一个结点。 第一个结点。 第一个结点
void InOrderTraverse_Thr (BiThrTree T, Status (*Visit)(TElemType e)) // p指向根结点 { p = T->lchild; 指向根结点 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进至其右子树根 进至其右子树根 }
typedef struct BiThrNod { TElemType data; struct BiThrNode *lchild, *rchild; // 左右指针 PointerThr LTag, RTag; // 左右标志 } BiThrNode, *BiThrTree;
二、线索链表的遍历算法: 线索链表的遍历算法
相关文档
最新文档