[数据结构]第六章-树和二叉树(读书笔记3)
来源:互联网 发布:windows gif 录制 编辑:程序博客网 时间:2024/06/06 00:16
线索二叉树
二叉树遍历的缺点:当以二叉树链表作为存储结构时,只能找到结点的左右孩子信息,而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得到。
如何保存这种在遍历过程中得到的信息呢?一个最简单的办法是在每个结点上增加两个指针域fwd和bkwd,分别指示结点在任一次序遍历时得到的前驱和后继信息。
二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱和后继的指针,叫做线索。加上线索的二叉树称之为线索二叉树(Threaded Binary Tree)。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化。
线索二叉树通过设置LTAG,RTAG标志,并事先线索化来提高整个二叉树的遍历速度,是个典型的牺牲空间来提升速度的例子。线索二叉树方便查找一个结点在访问次序上的前后邻居。
LTag = 0 lchild域指示结点的左孩子
LTag = 1 lchild域指示结点的前驱
RTag = 0 lchild域指示结点的右孩子
RTag = 1 lchild域指示结点的后继
在线索树上进行遍历,只要先找到序列中结点,然后依次找结点后继直至其后继为空时为止。
根据中序遍历的规律可知,结点的后继应是遍历其右子树时访问的第一个结点。即右子树中最左下的结点。在中序线索二叉树上遍历二叉树,虽则时间复杂度亦为O(n),但常数因子要小很多,且不需要设栈。因此,若在某程序中所用二叉树需经常遍历或查找结点在遍历所得线性序列中的前驱和后继,则应采用线索链表作存储结构。
由于线索化的实质是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历时才能得到,因此线索化的过程即为在遍历的过程中修改空指针的过程。
/*Link == 0 指针 Thread == 1 线索*/typedef enum PointTag {Link,Thread}PointerTag;typedef struct BiThrNode{TElemType data;struct BiThrNode *lchild, *rchild;/*左右孩子指针*/PointerTagLTag,RTag;/*左右标志*/}BiThrNode,*BiThrTree;Status CreateBiThrTree(BiThrTree *T){ /* 按先序输入二叉线索树中结点的值,构造二叉线索树T *//* 0(整型)/空格(字符型)表示空结点 */TElemType h;#if CHARscanf("%c",&h);#elsescanf("%d",&h);#endifif(h == NIL){*T=NULL;}else{*T=(BiThrTree)malloc(sizeof(BiThrNode));if(!*T){exit(OVERFLOW);}(*T)->data = h; /* 生成根结点(先序) */CreateBiThrTree(&(*T)->lchild); /* 递归构造左子树 */if((*T)->lchild){ /* 有左孩子 */(*T)->LTag = Link;}CreateBiThrTree(&(*T)->rchild); /* 递归构造右子树 */if((*T)->rchild){ /* 有右孩子 */(*T)->RTag = Link;}}return OK;}BiThrTree pre; /* 全局变量,始终指向刚刚访问过的结点 */void InThreading(BiThrTree p){if (p){/* 中序遍历进行中序线索化。算法6.7 */InThreading(p->lchild);//左子树线索化if(!p->lchild){//前驱线索p->LTag = Thread;p->lchild = pre;}if(!pre->rchild){//后继线索pre->RTag = Thread;pre->rchild = p;}pre = p; /* 保持pre指向p的前驱 */InThreading(p->rchild);//右子树线索化}}Status InOrderThreading(BiThrTree Thrt, BiThrTree T){//中序遍历二叉树T,并将其中序线索化,Thrt指向头结点if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrTree)) )){exit(OVERFLOW);}//建头结点Thrt->LTag = Link;Thrt->RTag = Thread;//右指针回指Thrt->rchild = Thrt;//若二叉树空,则左指针回指if (T == NULL){Thrt->lchild = Thrt;}else{Thrt->lchild = T;pre = Thrt;InThreading(T);//最后一个结点线索化pre->rchild = Thrt;pre->RTag = Thread;Thrt->rchild = pre;}return OK;}Status InOrderTraverse_Thr(BiThrTree T,Status(*Visit)(TElemType)){/* 中序遍历二叉线索树T(头结点)的非递归算法。算法6.5 */BiThrTree p;//p指向根结点p = T->lchild;while(p != T){//空树或遍历结束时,p==Twhile(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;}Status vi(TElemType c){#if CHARprintf("%c ",c);#elseprintf("%d ",c);#endifreturn OK;}int _tmain(int argc, _TCHAR* argv[]){ BiThrTree H = NULL,T;#if CHARprintf("请按先序输入二叉树(如:ab三个空格表示a为根结点,b为左子树的二叉树)\n");#elseprintf("请按先序输入二叉树(如:1 2 0 0 0表示1为根结点,2为左子树的二叉树)\n");#endifCreateBiThrTree(&T); /* 按先序产生二叉树 */InOrderThreading(H,T); /* 中序遍历,并中序线索化二叉树 */ printf("中序遍历(输出)二叉线索树:\n");InOrderTraverse_Thr(T,vi); /* 中序遍历(输出)二叉线索树 */printf("\n");return 0;}
- [数据结构]第六章-树和二叉树(读书笔记3)
- [数据结构]第六章-树和二叉树(读书笔记1)
- [数据结构]第六章-树和二叉树(读书笔记2)
- [数据结构]第六章-树和二叉树(读书笔记4)
- 数据结构 第六章 树和二叉树
- 数据结构现在学到第六章树和二叉树了
- 大话数据结构 第六章 树(读书笔记)
- 数据结构--第六章 遍历二叉树
- 数据结构 第六章--线索二叉树
- 算法入门经典第六章数据结构—树和二叉树-1.二叉树的编号
- 数据结构编程笔记十六:第六章 树和二叉树 线索二叉树的实现
- 大话数据结构读书笔记——第六章 树
- 数据结构编程笔记十五:第六章 树和二叉树 树和二叉树的转换算法实现
- 数据结构编程笔记十七:第六章 树和二叉树 赫夫曼树的实现
- [读书笔记]树和二叉树[数据结构(c语言)严慧敏]
- (数据结构第六章)二叉树的顺序存储结构
- 数据结构第六章-二叉树顺序存储变链式存储
- 第六章 树和二叉树
- java 五子棋之人机对战思路详解
- CR0-4寄存器介绍
- 自定义ContentProvider
- Android内存调试命令
- github常见操作和常见错误!错误提示:fatal: remote origin already exists.
- [数据结构]第六章-树和二叉树(读书笔记3)
- Hibernate(七)——继承映射
- LogisticRegression.py 解析
- 反射
- float VS double
- ZZY的宠物(矩阵运算+快速幂)
- 创建一个圆角的JFrame
- 欢迎来我的博客
- HDU-2602-Bone Collector