线索二叉树 —— 利用二叉树二叉链结构中的空链域,储存某种遍历次序下每个带空链域的结点的前驱(后继)结点的指针
数据结构课代码实现 之 中序线索二叉树
简要理解: 设p为二叉树中的一个结点
若 p->lchild
为空 则储存中序遍历序列中 p
的前驱结点
若 p->rchild
为空 则储存中序遍历序列中 p
的后继结点
那么在遍历二叉树线索化时需要一个标记来指明结点的 lchild
与 rchild
指向的是 线索指针 还是 孩子指针
线索化后可以不使用递归遍历,且可以正反向遍历
具体理解 和 代码实现 声明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> #include <cstring> #include <cstdlib> #define OK 1 #define OVERFLOW -2 #define ERROR -1 typedef enum { Link, Thread} PointerTag; typedef struct BiThrNode // 线索二叉树比普通树多两个标记{ char data; struct BiThrNode *lchild , *rchild ; PointerTag ltag; PointerTag rtag; }BiThrNode, *BiThrTree; BiThrTree pre; bool visit (char x) { cout << x << " " ; return true ; }
先序遍历递归建立二叉树 这里踩了个坑,一开始忘记把所有结点的 ltag
和 rtag
全部初始化为 Link
,这会导致后面的 InOrderThreading
过程中产生错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int CreateBiThrTree (BiThrTree &T) { char ch; cin >> ch; if (ch == '#' ) T = NULL ; else { if (!(T = (BiThrNode *)malloc (sizeof (BiThrNode)))) exit (OVERFLOW); T->data = ch; T->ltag = Link; T->rtag = Link; CreateBiThrTree(T->lchild); CreateBiThrTree(T->rchild); } return OK; }
线索化过程 线索化的过程就是将中序遍历的过程中的访问操作改为线索化过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void InThreading (BiThrTree p) { if (p) { InThreading(p->lchild); if (!p->lchild) { p->ltag = Thread; p->lchild = pre; } if (!pre->rchild) { pre->rtag = Thread; pre->rchild = p; } pre = p; InThreading(p->rchild); } } int InOrderThreading (BiThrTree &Thrt,BiThrTree T) { if (!(Thrt = (BiThrNode *)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; InThreading(T); pre->rchild = Thrt; pre->rtag = Thread; Thrt->rchild = pre; } return OK; }
在 InThreading
中,遍历时,无法确认当前结点的后继结点,但是可以确定 pre
结点 的后继结点(也就是当前结点)
在 InOrderThreading
中对 Thrt
的头结点 ltag
与 rtag
的设置貌似并没有多大意义,在这个程序中使用线索非递归化遍历时并没有检查这两个标记,也许在其他地方有用…
中序非递归化遍历线索二叉树 正向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int InOrderTraverse_Thr (BiThrTree T,bool (* visit)(char x)) { BiThrTree p = T->lchild; while (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; } return OK; }
反向 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int reInOrderTraverse_Thr (BiThrTree T,bool (* visit)(char x)) { BiThrTree p = T->rchild; while (p != T) { while (p->rtag == Link) p = p->rchild; if (!visit(p->data)) return ERROR; while (p->ltag == Thread && p->lchild != T) { p = p->lchild; visit(p->data); } p = p->lchild; } return OK; }
这里还是比较好理解的
递归化遍历方法 为了验证,写一下递归化的遍历方法
1 2 3 4 5 6 7 8 void ooInThreading (BiThrTree p) { if (p == NULL ) return ; ooInThreading(p->lchild); visit(p->data); ooInThreading(p->rchild); }
main函数 给出一组数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int main () { BiThrTree Tre,Thre; CreateBiThrTree(Tre); ooInThreading(Tre); cout << endl ; InOrderThreading(Thre, Tre); InOrderTraverse_Thr(Thre, visit); cout << endl ; reInOrderTraverse_Thr(Thre, visit); return 0 ; }