【版权声明:转载请保留出处:blog.csdn.net/algorithm_only。邮箱:liuy0711@foxmail.com】
前面说到二叉树的二叉链表表示实现,当以二叉树作为存储结构时,只能找到节点的左右孩子信息,不能直接得到结点在任一序列中的前驱和后继信息,只有在遍历过程中才能得到这种信息。我们知道,在n个结点的二叉链表栈必定存在n+1个空链域,因此,可以利用这些空链域来存放这些结点信息。所以作如下规定:若结点右左子树,则其lchild域指向其左孩子,否则令lchild域指向其前驱;若结点有右子树,其rchild域指向其右孩子,否则指向其后继。以这种结构构成的二叉链表叫做线索链表。
- 线索链表的存储结构
typedef enum {link, thread} pointer_tag;
typedef struct tnode {
elemtype data;
struct tnode *lchild, *rchild;
pointer_tag ltag, rtag;
}bithrnode, *bithrtree;
- 二叉树的线索化(中序线索化)
int inorder_threading(bithrtree *thrt, bithrtree bt)
{
*thrt = (bithrtree) malloc (sizeof(bithrnode));
if (!*thrt)
exit(OVERFLOW);
/* 将头结点线索化 */
(*thrt)->ltag = link;
(*thrt)->rtag = thread;
(*thrt)->rchild = (*thrt);
if (!bt) /* 若二叉树为空,则将lchild指向自己 */
(*thrt)->lchild = (*thrt);
else {
(*thrt)->lchild = bt; /* 头结点左指针指向根结点 */
pre = (*thrt);
in_threading(bt); /* 中序遍历进行中序线索化 */
pre->rchild = *thrt;
pre->rtag = thread;
(*thrt)->rchild = pre;
}
return OK;
}
void in_threading(bithrtree t)
{
if (t) {
in_threading(t->lchild);
if (!t->lchild) {
t->ltag = thread;
t->lchild = pre;
}
if (!pre->rchild) {
pre->rtag = thread;
pre->rchild = t;
}
pre = t;
in_threading(t->rchild);
}
}
线索化的实质是将二叉链表中的空指针改为指向前驱或后继的线索,前驱和后继的信息是在遍历过程中才能得到,故线索化的过程即为在遍历过程中修改空指针的过程。
- 线索二叉树的遍历(中序)
int inorder_traverse_thr(bithrtree thrt, int (*visit)(bithrtree t))
{
bithrtree p;
p = thrt->lchild;
while (p != thrt) {
while (p->ltag == link)
p = p->lchild;
visit(p);
while (p->rtag == thread && p->rchild != thrt) {
p = p->rchild;
visit(p);
}
p = p->rchild;
}
return OK;
}
- 总结
在中序线索二叉树上遍历二叉树,虽然时间复杂度任然为O(n),但相比上节所讲遍历算法,不需要栈和队列等辅助空间。