线索二叉链表
线索二叉链表 来自于 二叉链表。一个二叉链表,如果存放n个结点,就一定有n+1个空指针域,而在线索链 表中,就让这n+1个空指针域有了用武之地。
空指针域 用于存放 某种遍历顺序下的 前驱或者后继的地址。
已知 一棵二叉树的结构:
|
|
|
孩子地址:B的地址 |
A |
孩子地址:D的地址 |
|
|
孩子地址:NULL |
B |
孩子地址: C的地址 |
|
孩子地址:NULL |
D |
孩子地址: E的地址 |
|
|
孩子地址:NULL |
C |
孩子地址:NULL |
|
孩子地址: F的地址 |
E |
孩子地址:NULL |
|
|
|
|
孩子地址:NULL |
F |
孩子地址:NULL |
|
其先序遍历结果:ABCDEF,对应的先序线索二叉树(二叉树的先序线索化)
|
|
|
孩子地址:B的地址 |
A |
孩子地址:D的地址 |
|
|
线索地址: A的地址 |
B |
孩子地址: C的地址 |
|
线索地址: C的地址 |
D |
孩子地址: E的地址 |
|
|
线索地址: B的地址 |
C |
线索地址: D的地址 |
|
孩子地址: F的地址 |
E |
线索地址: F的地址 |
|
|
|
|
线索地址: E的地址 |
F |
线索地址:NULL |
|
其中序遍历结果:BCADFE,对应的中序线索二叉树(二叉树的中序线索化)
|
|
|
孩子地址: B的地址 |
A |
孩子地址: D的地址 |
|
|
线索地址: NULL |
B |
孩子地址: C的地址 |
|
线索地址: A的地址 |
D |
孩子地址: E的地址 |
|
|
线索地址: B的地址 |
C |
线索地址: A的地址 |
|
孩子地址: F的地址 |
E |
线索地址: NULL |
|
|
|
|
线索地址: D的地址 |
F |
线索地址: E的地址 |
|
其后序遍历结果:CBFEDA,对应的后线索二叉树(二叉树的后序线索化)
|
|
|
孩子地址: B的地址 |
A |
孩子地址: D的地址 |
|
|
线索地址: C的地址 |
B |
孩子地址: C的地址 |
|
线索地址: E的地址 |
D |
孩子地址: E的地址 |
|
|
线索地址: NULL |
C |
线索地址: B的地址 |
|
孩子地址: F的地址 |
E |
线索地址: D的地址 |
|
|
|
|
线索地址: B的地址 |
F |
线索地址: E的地址 |
|
线索二叉树的代码定义:
#define TElemType char;
typedef enum{
Link,Thread
}PointerTag;
// 枚举类型PointerTag中的Link=0,标识 孩子指针;
// 枚举类型PointerTag中的Thread=1,标识 线索
typedef struct BiThrNode{
TElemType data;
struct BiThrNode *lc,*rc;
PointerTag LTag,RTag;
}BiThrNode, *BiThrTree;
说明:
如果某结点 有 左孩子,则LTag=Link=0,lc=左孩子的地址
没有 左孩子,则LTag=Thread=1,lc=此结点在某遍历顺序下的前驱结点的地址
(思考:为什么如果存线索,存的是前驱结点的地址,而不是后继结点的地址?)
如果某结点 有 右孩子,则RTag=Link=0,lc=右孩子的地址
没有 右孩子,则RTag=Thread=1,rc=此结点在某遍历顺序下的后继结点的地址
(同理思考:为什么如果存线索,存的是后继结点的地址,而不是前驱结点的地址?)