前面说到二叉树的二叉链表表示实现,当以二叉树作为存储结构时,只能找到节点的左右孩子信息,不能直接得到结点在任一序列中的前驱和后继信息,只有在遍历过程中才能得到这种信息。我们知道,在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),但相比上节所讲遍历算法,不需要栈和队列等辅助空间。