线索二叉树的详细实现(C++)
线索二叉树概述


寻找当前结点在中序下的后继

寻找当前结点在中序序列下的前驱

线索二叉树的结点类
- //线索二叉树结点类
- template<typename T>
- struct ThreadNode //结点类
- {
- int ltag, rtag; //左右子树标志位
- ThreadNode<T> *leftChild, *rightChild; //左孩子和右孩子
- T data; //结点存储的值
- ThreadNode(const T item) :data(item), leftChild(NULL), rightChild(NULL), ltag(), rtag() {} //结点类的构造函数
- };
线索二叉树的创建
- //使用前序遍历创建二叉树(未线索化)
- void CreateTree(ThreadNode<T>* &subTree)
- {
- T item;
- if (cin >> item)
- {
- if (item != RefValue)
- {
- subTree = new ThreadNode<T>(item); //构造结点
- if (subTree == NULL)
- {
- cout << "空间分配错误!" << endl;
- exit();
- }
- CreateTree(subTree->leftChild); //递归创建左子树
- CreateTree(subTree->rightChild); //递归创建右子树
- }
- else
- {
- subTree == NULL;
- }
- }
- }
- //中序遍历对二叉树进行线索化
- void createInThread(ThreadNode<T> *current, ThreadNode<T> * &pre)
- {
- if (current == NULL)
- {
- return;
- }
- createInThread(current->leftChild, pre); //递归左子树的线索化
- if (current->leftChild == NULL) //建立当前结点的前驱结点
- {
- current->leftChild = pre;
- current->ltag = ;
- }
- if (pre != NULL&&pre->rightChild == NULL) //建立当前结点的后继结点
- {
- pre->rightChild = current;
- pre->rtag = ;
- }
- pre = current; //用前驱记住当前的结点
- createInThread(current->rightChild, pre); //递归右子树的线索化
- }
- //中序遍历对创建好的普通二叉树进行中序线索化
- void CreateInThread()
- {
- ThreadNode<T> *pre = NULL; //第一个结点的左子树置为NULL
- if (root != NULL) {
- createInThread(root, pre);
- //处理中序遍历的最后一个结点,最后一个结点的右子树置为空
- pre->rightChild = NULL;
- pre->rtag = ;
- }
- }
中序线索化二叉树的成员函数
- //寻找中序下第一个结点
- ThreadNode<T> * First(ThreadNode<T> *current)
- //返回以*current为根的中序线索二叉树中序遍历的第一个结点
- {
- ThreadNode<T> *p = current;
- while (p->ltag == )
- {
- p = p->leftChild; //循环找到最左下角结点
- }
- return p;
- }
- //寻找中序下的后继结点
- ThreadNode<T>* Next(ThreadNode<T>* current)
- {
- ThreadNode<T>* p = current->rightChild;
- if(current->rtag==)
- {
- return First(p);
- }
- else
- {
- return p;
- }
- }
- //寻找中序下最后一个结点
- ThreadNode<T> * Last(ThreadNode<T> *current)
- //返回以*current为根的中序线索二叉树中序遍历的最后一个结点
- {
- ThreadNode<T> *p = current;
- while (p->rtag==)
- {
- p = p->rightChild;
- }
- return p;
- }
- //寻找结点在中序下的前驱结点
- ThreadNode<T>* Prior(ThreadNode<T>* current)
- {
- ThreadNode<T>* p = current->leftChild;
- if (current->ltag==)
- {
- return Last(p);
- }
- else
- {
- return p;
- }
- }
中序线索化二叉树上执行中序遍历的算法
- //中序线索化二叉树上执行中序遍历的算法
- void InOrder(ThreadNode<T>* p)
- {
- for (p=First(root);p!=NULL;p=Next(p))
- {
- cout << p->data<<" ";
- }
- cout << endl;
- }
中序线索化二叉树上实现前序遍历的算法
- void PreOrder(ThreadNode<T>* p)
- {
- while (p!=NULL)
- {
- cout << p->data<<" "; //先访问根节点
- if (p->ltag==)
- {
- p = p->leftChild; //有左子树,即为后继
- }
- else if(p->rtag==) //否则,有右子树,即为后继
- {
- p = p->rightChild;
- }
- else //无左右子树
- {
- while (p!=NULL&&p->rtag==) //检测后继线索
- {
- p = p->rightChild; //直到找到有右子树的结点
- }
- if (p!=NULL)
- {
- p = p->rightChild; //该结点的右子树为后继
- }
- }
- }
- cout << endl;
- }
中序线索化二叉树后序遍历的算法
- //中序线索二叉树的后序遍历算法
- void PostOrder(ThreadNode<T>* p)
- {
- ThreadNode<T>* t = p;
- while (t->ltag==||t->rtag==) //寻找后续第一个结点
- {
- if(t->ltag==)
- {
- t = t->leftChild;
- }
- else if(t->rtag==)
- {
- t = t->rightChild;
- }
- }
- cout << t->data<<" "; //访问第一个结点
- while ((p=Parent(t))!=NULL) //每次都先找到当前结点的父结点
- {
- //若当前结点是父节点的右子树或者当前结点是左子树,但是这个父节点没有右子树,则后续下的后继为改父节点
- if (p->rightChild==t||p->rtag==)
- {
- t = p;
- }
- //否则,在当前结点的右子树(如果存在)上重复执行上面的操作
- else
- {
- t = p->rightChild;
- while (t->ltag==||t->rtag==)
- {
- if (t->ltag==)
- {
- t = t->leftChild;
- }
- else if (t->rtag==)
- {
- t = t->rightChild;
- }
- }
- }
- cout << t->data << " ";
- }
- }
在中序线索二叉树中求父节点

- //在中序线索化二叉树中求父节点
- ThreadNode<T>* Parent(ThreadNode<T>* t)
- {
- ThreadNode<T>* p;
- if(t==root) //根节点无父节点
- {
- return NULL;
- }
- for (p = t; p->ltag == ; p = p->leftChild); //求*t为根的中序下的第一个结点p
- //情况1
- if (p->leftChild!=NULL) //当p左子树指向不为空
- {
- //令p为p的左子树指向的结点,判断此结点是否并且此节点的左右子树结点的指向都不为t,再将p为p的右孩子结点
- for (p = p->leftChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->rightChild);
- }
- //情况2
- //如果上面的循环完了,由于是p==NULL结束的循环,没有找到与t相等的结点,就是一直找到了中序线索化的第一个结点了,这时候这种就要用到情况2的方法
- if (p==NULL||p->leftChild==NULL)
- {
- //找到*t为根的中序下的最后一个结点
- for (p = t; p->rtag == ; p = p->rightChild);
- //让后让他指向最后一个结点指向的结点,从这个结点开始,以此判断它的左孩子孩子和右孩子是否和t相等
- for (p = p->rightChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->leftChild);
- }
- return p;
- }
完整代码
- //线索二叉树
- template<typename T>
- struct ThreadNode //结点类
- {
- int ltag, rtag; //左右子树标志位
- ThreadNode<T> *leftChild, *rightChild; //左孩子和右孩子
- T data; //结点存储的值
- ThreadNode(const T item) :data(item), leftChild(NULL), rightChild(NULL), ltag(), rtag() {} //结点类的构造函数
- };
- template<typename T>
- class ThreadTree
- {
- public:
- //构造函数(普通)
- ThreadTree() :root(NULL) {}
- //指定结束标志RefValue的构造函数
- ThreadTree(T value) :RefValue(value), root(NULL) {}
- //使用前序遍历创建二叉树(未线索化)
- void CreateTree() { CreateTree(root); }
- //中序遍历对创建好的普通二叉树进行中序线索化
- void CreateInThread()
- {
- ThreadNode<T> *pre = NULL; //第一个结点的左子树置为NULL
- if (root != NULL) {
- createInThread(root, pre);
- //处理中序遍历的最后一个结点,最后一个结点的右子树置为空
- pre->rightChild = NULL;
- pre->rtag = ;
- }
- }
- //线索化二叉树上执行中序遍历的算法
- void InOrder() { InOrder(root); }
- //中序线索化二叉树上实现前序遍历的算法
- void PreOrder() { PreOrder(root); }
- //中序线索二叉树的后序遍历算法
- void PostOrder() { PostOrder(root); }
- private:
- //使用前序遍历创建二叉树(未线索化)
- void CreateTree(ThreadNode<T>* &subTree)
- {
- T item;
- if (cin >> item)
- {
- if (item != RefValue)
- {
- subTree = new ThreadNode<T>(item); //构造结点
- if (subTree == NULL)
- {
- cout << "空间分配错误!" << endl;
- exit();
- }
- CreateTree(subTree->leftChild); //递归创建左子树
- CreateTree(subTree->rightChild); //递归创建右子树
- }
- else
- {
- subTree == NULL;
- }
- }
- }
- //中序遍历对二叉树进行线索化
- void createInThread(ThreadNode<T> *current, ThreadNode<T> * &pre)
- {
- if (current == NULL)
- {
- return;
- }
- createInThread(current->leftChild, pre); //递归左子树的线索化
- if (current->leftChild == NULL) //建立当前结点的前驱结点
- {
- current->leftChild = pre;
- current->ltag = ;
- }
- if (pre != NULL&&pre->rightChild == NULL) //建立当前结点的后继结点
- {
- pre->rightChild = current;
- pre->rtag = ;
- }
- pre = current; //用前驱记住当前的结点
- createInThread(current->rightChild, pre); //递归右子树的线索化
- }
- //寻找中序下第一个结点
- ThreadNode<T> * First(ThreadNode<T> *current) //返回以*current为根的中序线索二叉树中序遍历的第一个结点
- {
- ThreadNode<T> *p = current;
- while (p->ltag == )
- {
- p = p->leftChild; //循环找到最左下角结点
- }
- return p;
- }
- //寻找中序下的后继结点
- ThreadNode<T>* Next(ThreadNode<T>* current)
- {
- ThreadNode<T>* p = current->rightChild;
- if(current->rtag==)
- {
- return First(p);
- }
- else
- {
- return p;
- }
- }
- //寻找中序下最后一个结点
- ThreadNode<T> * Last(ThreadNode<T> *current) //返回以*current为根的中序线索二叉树中序遍历的最后一个结点
- {
- ThreadNode<T> *p = current;
- while (p->rtag==)
- {
- p = p->rightChild;
- }
- return p;
- }
- //寻找结点在中序下的前驱结点
- ThreadNode<T>* Prior(ThreadNode<T>* current)
- {
- ThreadNode<T>* p = current->leftChild;
- if (current->ltag==)
- {
- return Last(p);
- }
- else
- {
- return p;
- }
- }
- //在中序线索化二叉树中求父节点
- ThreadNode<T>* Parent(ThreadNode<T>* t)
- {
- ThreadNode<T>* p;
- if(t==root) //根节点无父节点
- {
- return NULL;
- }
- for (p = t; p->ltag == ; p = p->leftChild); //求*t为根的中序下的第一个结点p
- //情况1
- if (p->leftChild!=NULL) //当p左子树指向不为空
- {
- //令p为p的左子树指向的结点,判断此结点是否并且此节点的左右子树结点的指向都不为t,再将p为p的右孩子结点
- for (p = p->leftChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->rightChild);
- }
- //情况2
- //如果上面的循环完了,由于是p==NULL结束的循环,没有找到与t相等的结点,就是一直找到了中序线索化的第一个结点了,这时候这种就要用到情况2的方法
- if (p==NULL||p->leftChild==NULL)
- {
- //找到*t为根的中序下的最后一个结点
- for (p = t; p->rtag == ; p = p->rightChild);
- //让后让他指向最后一个结点指向的结点,从这个结点开始,以此判断它的左孩子孩子和右孩子是否和t相等
- for (p = p->rightChild; p != NULL&&p->leftChild != t&&p->rightChild != t; p = p->leftChild);
- }
- return p;
- }
- //中序线索化二叉树上执行中序遍历的算法
- void InOrder(ThreadNode<T>* p)
- {
- for (p=First(root);p!=NULL;p=Next(p))
- {
- cout << p->data<<" ";
- }
- cout << endl;
- }
- //中序线索化二叉树上实现前序遍历的算法
- void PreOrder(ThreadNode<T>* p)
- {
- while (p!=NULL)
- {
- cout << p->data<<" "; //先访问根节点
- if (p->ltag==)
- {
- p = p->leftChild; //有左子树,即为后继
- }
- else if(p->rtag==) //否则,有右子树,即为后继
- {
- p = p->rightChild;
- }
- else //无左右子树
- {
- while (p!=NULL&&p->rtag==) //检测后继线索
- {
- p = p->rightChild; //直到找到有右子树的结点
- }
- if (p!=NULL)
- {
- p = p->rightChild; //该结点的右子树为后继
- }
- }
- }
- cout << endl;
- }
- //中序线索二叉树的后序遍历算法
- void PostOrder(ThreadNode<T>* p)
- {
- ThreadNode<T>* t = p;
- while (t->ltag==||t->rtag==) //寻找后续第一个结点
- {
- if(t->ltag==)
- {
- t = t->leftChild;
- }
- else if(t->rtag==)
- {
- t = t->rightChild;
- }
- }
- cout << t->data<<" "; //访问第一个结点
- while ((p=Parent(t))!=NULL) //每次都先找到当前结点的父结点
- {
- //若当前结点是父节点的右子树或者当前结点是左子树,但是这个父节点没有右子树,则后续下的后继为改父节点
- if (p->rightChild==t||p->rtag==)
- {
- t = p;
- }
- //否则,在当前结点的右子树(如果存在)上重复执行上面的操作
- else
- {
- t = p->rightChild;
- while (t->ltag==||t->rtag==)
- {
- if (t->ltag==)
- {
- t = t->leftChild;
- }
- else if (t->rtag==)
- {
- t = t->rightChild;
- }
- }
- }
- cout << t->data << " ";
- }
- }
- private:
- //树的根节点
- ThreadNode<T> *root;
- T RefValue;
- };
测试函数
- int main(int argc, char* argv[])
- {
- //abc##de#g##f###
- ThreadTree<char> tree('#');
- tree.CreateTree();
- tree.CreateInThread();
- tree.InOrder();
- tree.PreOrder();
- tree.PostOrder();
- }
线索二叉树的详细实现(C++)的更多相关文章
- 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构
在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...
- 数据结构《9》----Threaded Binary Tree 线索二叉树
对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为 n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...
- 线索二叉树Threaded binary tree
摘要 按照某种遍历方式对二叉树进行遍历,可以把二叉树中所有结点排序为一个线性序列.在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点:除最后一个结点外每一个结点有且仅有一个直接后继结点.这 ...
- 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化
遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...
- 树和二叉树->线索二叉树
文字描述 从二叉树的遍历可知,遍历二叉树的输出结果可看成一个线性队列,使得每个结点(除第一个和最后一个外)在这个线形队列中有且仅有一个前驱和一个后继.但是当采用二叉链表作为二叉树的存储结构时,只能得到 ...
- 图解中序遍历线索化二叉树,中序线索二叉树遍历,C\C++描述
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)
本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...
- 数据结构之线索二叉树——C语言实现
线索二叉树操作 (1) 线索二叉树的表示:将每个节点中为空的做指针与右指针分别用于指针节点的前驱和后续,即可得到线索二叉树. (2) 分类:先序线索二叉树,中序线索二叉树,后续线索二叉树 (3) 增 ...
- 后序线索二叉树中查找结点*p的后继
在后序线索二叉树中查找结点*p的后继: 1.若结点*p为根,则无后继:2.若结点*p为其双亲的右孩子,则其后继为其双亲:3.若结点*p为其双亲的左孩子,且双亲无右子女,则其后继为其双亲:4.若结点*p ...
随机推荐
- 浅谈C#委托的用法-delegate[转]
一.委托的概念 委托和类一样是一种用户自定义类型,它存储的就是一系列具有相同签名和返回类型的方法的地址,调用委托的时候,它所包含的所有方法都会被执行. 借用百度上的一句话概括:委托是一个类,它定义了方 ...
- C# 读取Excel到DataTable两种方式对比
方式一 OLEDB读取 数据库引擎 优点:读取速度快,依据sheet排序读取 缺点:对于Excel版本依赖强,无法读取指定sheet 错误提示:本地计算机未指定 Microsoft.ACE.OLEDB ...
- Codeforces Round #616 (Div. 2) B. Array Sharpening
t题目链接:http://codeforces.com/contest/1291/problem/B 思路: 用极端的情况去考虑问题,会变得很简单. 无论是单调递增,单调递减,或者中间高两边低的情况都 ...
- HDU1548 奇怪的电梯(bfs求最少)
There is a strange lift.The lift can stop can at every floor as you want, and there is a number Ki(0 ...
- 假期学习【十】首都之窗百姓信件JavaWweb+Echarts图表展示
今天主要对昨天爬取的数据进行处理,处理后用Echart图表展示, 效果如下:
- 记录 Docker 的学习过程 (dockerfile自动制作镜像)
自动制作镜像 通过编写dockerfile来自动创建镜像 #vi Dockerfile #编辑dockerfile文件,一定要以这个名字命名 #cat Dockerfile #导入哪个基础镜像FROM ...
- Git学习笔记-上传一个新的项目到GitHub上
前提: 已有Github账号,已在Github上建立了仓库,已在Github上配置了SSH,已上传过一些项目到Github上 目标: 目前有一个新的项目,需要上传到github上 我的做法记录: 1. ...
- android 代码实现模拟用户点击、滑动等操作
/** * 模拟用户点击 * * @param view 要触发操作的view * @param x 相对于要操作view的左上角x轴偏移量 * @param y 相对于要操作view的左上角y轴偏移 ...
- 利用Marshal来管理非托管资源
void MarshalChartDemo() { string name = "xuwei"; IntPtr pName = Marshal.AllocHGlobal(name. ...
- day30 NFS服务器概述
02. NFS存储服务概念介绍 NFS是Network File System的缩写,中文意思是网络文件共享系统, 它的主要功能是通过网络(一般是局域网)让不同的主机系统之间可以共享文件或目录 存储服 ...