线索化二叉树
2016-11-12 16:42
197 查看
概念
普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得。若可将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树了。
线索化的目的就是将二叉树像普通双向链表一样遍历
线索化过程
就是在遍历过程(假设是中序遍历)中修改空指针的过程:将空的lchild改为结点的直接前驱;
将空的rchild改为结点的直接后继。
创建二叉树可以使用先序遍历的方式
代码实现
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <io.h> #include <math.h> #include <time.h> #define OK 1 #define ERROR 0 typedef char TElemType;//树的每一个节点里面的数据(这里可以用void*实现数据类型的封装) typedef int Status;/* Status是函数的类型,其值是函数结果状态代码,如OK等 */ typedef enum { Link, Thread } PointerTag;/* Link==0表示指向左右孩子指针, */ /* Thread==1表示指向前驱或后继的线索 */ typedef struct _biThrNode/* 二叉线索存储结点结构 */ { TElemType data;/* 结点数据 */ struct _biThrNode *lchild, *rchild;/* 左右孩子指针 */ PointerTag LTag,RTag;/* 左右标志 */ }BiThrNode,*BiThrTree; TElemType Nil = '#';//表示没有子节点 /*访问一个节点的数据域*/ Status visit(TElemType e) { printf("%c",e); return OK; } /* 按前序输入二叉线索树中结点的值,构造二叉线索树T */ Status CreateBiThrTree(BiThrTree * T) { TElemType ch;//缓存输入的字符 BiThrTree tmp = NULL; scanf("%c",&ch);//接收输入 if (ch == Nil)//如果输入的是'#',表示没有子节点 { tmp = NULL;//根节点指向空表示空树 //(每一次递归,根节点会变化,这里的根节点可能指的是左子树或者右子树的根) } else{ tmp = (BiThrTree)malloc(sizeof(BiThrNode));//为根节点分配内存 if (!tmp) exit(OVERFLOW); tmp->data = ch;//数据域赋值 CreateBiThrTree(&(tmp->lchild));//递归创建左子树 if (tmp->lchild)/* 有左孩子 */ tmp->LTag = Link;//标志设置成链表 CreateBiThrTree(&(tmp->rchild));//递归创建右子树 if (tmp->rchild) tmp->RTag = Link; } *T = tmp;//将实参指向新创建好的二叉树的根节点 return OK; } BiThrTree pre;/* 全局变量,始终指向刚刚访问过的结点 */ /* 中序遍历进行中序线索化 */ 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;/* 前驱右孩子指针指向后继(当前结点p) */ } pre = p;/* 保持pre指向p的前驱 */ InThreading(p->rchild); /* 递归右子树线索化 */ } } /* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点 */ Status InOrderThreading(BiThrTree * head,BiThrTree T) { BiThrTree tmp = NULL;//辅助指针变量,最后将其值传递给参数head指向的内存空间 tmp = (BiThrTree)malloc(sizeof(BiThrNode));//为头节点分配内存 if (tmp == NULL) exit(OVERFLOW); /* 建头结点 */ tmp->LTag = Link; tmp->RTag = Thread; tmp->rchild = tmp;/* 右指针回指 */ if (!T)/* 若二叉树空,则左指针回指 */ tmp->lchild = tmp; else { tmp->lchild = T;//头结点的左孩子指向真正二叉树的起始位置(根节点) pre = tmp;//pre指向头结点 InThreading(T);/* 中序遍历进行中序线索化 */ pre->RTag = Thread;/* 最后一个结点线索化 */ pre->rchild = tmp; tmp->rchild = pre;//头结点的右孩子指向最后一个节点 } (*head) = tmp;//将头结点跑出到主调函数 return OK; } /* 中序遍历二叉线索树T(头结点)的非递归算法 */ Status InOrderTraverse_Thr(BiThrTree T) { BiThrTree p = NULL; if (T == NULL)//合法性 exit(OVERFLOW); p = T->lchild;/* p指向根结点 */ while (p != T)/* 空树或遍历结束时,p==T */ { while (p->LTag == Link)//左子树不为空,一直往左走,直到左子树为空 p = p->lchild; if (!visit(p->data))/* 访问其左子树为空的结点 */ exit(OVERFLOW); while (p->RTag== Thread && p->rchild != T)//节点的右孩子如果标记为线索化, //且右孩子(后继)没有指向头结点,表示没有遍历结束 { p = p->rchild;//当前节点已被访问,往后遍历 if (!visit(p->data)) /* 访问后继结点 */ exit(OVERFLOW); } p = p->rchild;//更新右子树的访问 } return OK; } int main() { BiThrTree H, T; printf("请按前序输入二叉树(如:'ABDH##I##EJ###CF##G##')\n"); CreateBiThrTree(&T); /* 按前序产生二叉树 */ InOrderThreading(&H, T); /* 中序遍历,并中序线索化二叉树 */ printf("中序遍历(输出)二叉线索树:\n"); InOrderTraverse_Thr(H); /* 中序遍历(输出)二叉线索树 */ printf("\n"); system("pause"); return 0; }
相关文章推荐
- 线索化二叉树
- 数据结构——前序线索化二叉树
- 第11周项目1 验证算法(3)中序线索化二叉树的算法验证
- 第11周项目1-验证算法(3)中序线索化二叉树的算法验证
- 第十一周项目1——二叉树算法验证(3) 中序线索化二叉树的算法验证
- 第十一周项目1 - 二叉树算法验证(3)中序线索化二叉树的算法验证
- 第十一周项目1——二叉树算法验证(3) 中序线索化二叉树的算法验证
- 第11周项目1-(3)中序线索化二叉树的算法验证
- 线索化二叉树
- 二叉树的线索化
- 【每日一题-17】线索化二叉树与单例模式
- 线索化二叉树
- 中序线索化二叉树
- 中序线索化二叉树以及中序遍历线索化二叉树、倒中序遍历线索化二叉树
- 第11周 项目1-中序线索化二叉树的算法验证
- 第十一周 项目一(3)-中序线索化二叉树的算法验证
- 数据结构-线索化二叉树
- 【第11周 项目1 - 二叉树算法验证(3)中序线索化二叉树的算法验证】
- C语言实现中序线索化二叉树并遍历
- 第十周 项目4 - 线索化二叉树(中序)