【线索化】
对二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化,依据二叉树遍历次序的不同,分为前序、中序、后序三种线索二叉树
线索化的核心是建立线索,之后无论是何种形式的线索二叉树,只要在其前、中、序遍历递归过程中,更改线索建立的位置即可
在建立线索时,需要一个前驱指针 pre
,用于指向当前节点 p
的前驱结点
- 若当前结点
p
没有左孩子:让 p
的左孩子指针指向当前结点的前驱 pre
,以建立前驱关系
- 若前驱结点
pre
非空,且没有右孩子:让 pre
的右孩子指针指向当前结点 p
,以建立后继关系
同时,在每次完成线索建立后,令 pre
指向 p
,以保持 pre
总是指向当前结点的前驱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| typedef struct ThNode { int data; struct ThNode *lchild; struct ThNode *rchild; int ltag, rtag; } ThNode, *ThTree;
void buildThread(ThNode *p, ThNode *&pre) { if (p->lchild == NULL) { p->lchild = pre; p->ltag = 1; }
if (pre != NULL) { if (pre->rchild == NULL) { pre->rchild = p; pre->rtag = 1; } pre = p; } }
|
【中序线索二叉树】
对于中序线索二叉树来说,其按照中序遍历顺序,先访问左子树,再访问根结点,最后再访问右子树
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| void inThread(ThTree p, ThNode *&pre) { inThread(p->lchild, pre); buildThread(p, pre); inThread(p->rchild, pre); } void createInThreadTree(ThTree root) { if (root == NULL) return;
ThTree pre = NULL; inThread(root, pre); if (pre->rchild == NULL) pre->rtag = 1; }
|
【前序线索二叉树】
对于前序线索二叉树来说,其按照前序遍历顺序,先访问根结点,再访问左子树,最后再访问右子树
在线索化过程时,由于进入递归函数后会先进行线索化,因此,这相较于中序线索二叉树来说,可能导致 pre
出现绕圈问题
为避免可能出现的绕圈,要加一个判断,即当左孩子指针 lchild
不是前驱线索时,才进行左子树线索化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void preThread(ThTree p, ThNode *&pre) { buildThread(p, pre); if (p->ltag == 0) preThread(p->lchild, pre); preThread(p->rchild, pre); } void createPreThreadTree(ThTree root) { if (root == NULL) return;
ThTree pre = NULL; preThread(root, pre); if (pre->rchild == NULL) pre->rtag = 1; }
|
【后序线索二叉树】
对于后序线索二叉树来说,其按照后序遍历顺序,先访问左子树,再访问右子树,最后再访问根结点
1 2 3 4 5 6 7 8 9 10 11 12 13
| void postThread(ThTree p, ThNode *&pre) { postThread(p->lchild, pre); postThread(p->rchild, pre); buildThread(p, pre); } void createPostThreadTree(ThTree root) { if (root == NULL) return; ThTree pre = NULL; postThread(root, pre); if (pre->rchild == NULL) pre->rtag = 1; }
|