贴出学习C++数据结构线索化二叉树的过程,

方便和我一样的新手进行测试和学习

同时欢迎各位大神纠正。

不同与普通二叉树的地方会用背景色填充

//BinTreeNode_Thr.h

 enum PointTag
{Link,Thread}; template<typename ElemType>
struct BinTreeNode
{
ElemType data; //数据元素
PointTag LTag,RTag; //左标志,右标志
BinTreeNode<ElemType> *leftChild; //指向左孩子的指针
BinTreeNode<ElemType> *rightChild; //指向右孩子的指针
//函数构造
BinTreeNode();
BinTreeNode(const ElemType &val,
BinTreeNode<ElemType> *lChild=NULL,
BinTreeNode<ElemType> *rChild=NULL);
BinTreeNode<ElemType> &operator =(const BinTreeNode<ElemType> &copy);
}; template<typename ElemType>
BinTreeNode<ElemType>::BinTreeNode()
{
leftChild=rightChild=NULL;
LTag=RTag=Link; //此处初始化为Link,即存在孩子
} template<typename ElemType>
BinTreeNode<ElemType>::BinTreeNode(const ElemType &val,
BinTreeNode<ElemType> *lChild,
BinTreeNode<ElemType> *rChild)
{
data=val;
LTag=RTag=Link; //初始化为Link
leftChild=lChild;
rightChild=rChild;
} template<typename ElemType>
BinTreeNode<ElemType> &BinTreeNode<ElemType>::operator =(const BinTreeNode<ElemType> &copy)
{
data=copy.data;
leftChild=copy.leftChild;
rightChild=copy.leftChild;
LTag=copy.LTag;
RTag=copy.RTag;
}

//BinaryTree_Thr.h

 #include"BinTreeNode_Thr.h"
template<typename ElemType>
class BinaryTree_Thr
{
protected:
//数据成员
BinTreeNode<ElemType> *root;
//辅助函数
BinTreeNode<ElemType> *CopyTreeHelp(const BinTreeNode<ElemType> *r);//复制二叉树
void DestroyHelp(BinTreeNode<ElemType> *&r);//销毁r为根的二叉树
void PreThreadingHelp(BinTreeNode<ElemType> *p,BinTreeNode<ElemType> *&pre); //先序线索化
void InThreadingHelp(BinTreeNode<ElemType> *p,BinTreeNode<ElemType> *&pre); //中序线索化
void CreateBTreeHelp(BinTreeNode<ElemType> *&r,ElemType pre[],ElemType in[],int,int,int,int);//用中序和先序序列构造树
public:
BinaryTree_Thr(){root=NULL}//无参构造
BinaryTree_Thr(BinTreeNode<ElemType> *r){ root=r;}//建立以r为根的二叉树
virtual ~BinaryTree_Thr();//有指针自定义虚构,且用虚虚构
BinaryTree_Thr<ElemType> &CreateBTree(ElemType pre[],ElemType in[],int n); //构造树
void PreTreading();//先序线索化
void InTreading();//中序线索化
void PreOrderTraverse_Thr(void (*visit) (const ElemType &))const; //先序遍历
void InOrderTraverse_Thr(void (*visit) (const ElemType &))const; //中序遍历
void LevelOrder(void (*visit) (const ElemType &))const;
BinaryTree_Thr<ElemType> &operator =(const BinaryTree_Thr<ElemType> &copy);//重载赋值运算符
}; //Copy
template<typename ElemType>
BinTreeNode<ElemType> *BinaryTree_Thr<ElemType>::CopyTreeHelp(const BinTreeNode<ElemType> *r)
{
BinTreeNode<ElemType> *cur;
if(r==NULL) cur=NULL;
else
{
BinTreeNode<ElemType> *lChild=CopyTreeHelp(r->leftChild);//复制左子树
BinTreeNode<ElemType> *rChild=CopyTreeHelp(r->rightChild);//复制右子树
cur=new BinTreeNode<ElemType>(r->data,lChild,rChild);
//复制根节点
}
return cur;
} template<typename ElemType>
void BinaryTree_Thr<ElemType>::InThreadingHelp(BinTreeNode<ElemType> *p,BinTreeNode<ElemType> *&pre)//中序遍历
{
if(p)
{
if(p->LTag==Link)
InThreadingHelp(p->leftChild,pre); //线索化左子树.
if(!p->leftChild) //左孩子空
{
p->LTag=Thread;
p->leftChild=pre;
}
if(!pre->rightChild) //前驱 的右孩子空
{
pre->RTag=Thread;
pre->rightChild=p;
}
pre=p;
if(p->RTag==Link)
InThreadingHelp(p->rightChild,pre); //线索化右子树
} } template<typename ElemType>
void BinaryTree_Thr<ElemType>::PreThreadingHelp(BinTreeNode<ElemType> *p,BinTreeNode<ElemType> *&pre)//先序遍历
{
if(p)
{
if(!p->leftChild) //左孩子空
{
p->LTag=Thread;
p->leftChild=pre;
}
if(!pre->rightChild) //前驱 的右孩子空
{
pre->RTag=Thread;
pre->rightChild=p;
}
pre=p;
if(p->LTag==Link)
PreThreadingHelp(p->leftChild,pre); //线索化左子树.
if(p->RTag==Link)
PreThreadingHelp(p->rightChild,pre); //线索化右子树
} } template<typename ElemType>
void BinaryTree_Thr<ElemType>::DestroyHelp(BinTreeNode<ElemType> *&r)
{
if(r!=NULL)
{
if(r->LTag==Link)
DestroyHelp(r->leftChild);
if(r->RTag==Link)
DestroyHelp(r->rightChild);
delete r;
r=NULL;
}
} //虚构
template<typename ElemType>
BinaryTree_Thr<ElemType>::~BinaryTree_Thr()
{
DestroyHelp(root);
} template<typename ElemType>
//Thr为头节点,T为根.
void BinaryTree_Thr<ElemType>::InTreading()
{
BinTreeNode<ElemType> *pre=root;
InThreadingHelp(root,pre); //中序线索化
if(pre->rightChild==NULL)
pre->RTag=Thread; //处理最后一个节点
} template<typename ElemType>
void BinaryTree_Thr<ElemType>::PreTreading()
{
BinTreeNode<ElemType> *pre=root;
PreThreadingHelp(root,pre); //先序线索化
if(pre->rightChild==NULL)
pre->RTag=Thread; //处理最后一个节点
} template<typename ElemType>
void print(const ElemType &e )
{
cout<<e<<" ";
} template<typename ElemType>
void BinaryTree_Thr<ElemType>::InOrderTraverse_Thr(void (*visit) (const ElemType &))const
{
visit=print;
if(root!=NULL){
BinTreeNode<ElemType> *p=root; //p指向根
while(p->LTag==Link) p=p->leftChild; //左走至最左下角
while(p)
{
(*visit)(p->data); //访问结点元素
if(p->RTag==Thread) //右孩子为线索,则p指向后继
{
p=p->rightChild;
}
else //右孩子存在
{
p=p->rightChild; //遍历右孩子
while(p->LTag==Link)
p=p->leftChild;
}
}
}
} template<typename ElemType>
void BinaryTree_Thr<ElemType>::PreOrderTraverse_Thr(void (*visit) (const ElemType &))const
{
visit=print;
if(root!=NULL){
BinTreeNode<ElemType> *p=root; //p指向根
while(p)
{
(*visit)(p->data);
if(p->RTag==Thread)
p=p->rightChild;
else
{
if(p->LTag==Link)
p=p->leftChild;
else
p=p->rightChild;
}
}
}
} template<typename ElemType>
void BinaryTree_Thr<ElemType>::CreateBTreeHelp(BinTreeNode<ElemType> *&r,
ElemType pre[],ElemType in[],
int preLeft,int preRight,int inLeft,int inRight) {
if(preLeft>preRight||inLeft>inRight)
r=NULL;
else
{
r=new BinTreeNode<ElemType>(pre[preLeft]);//生成根结点
int mid=inLeft;
while(in[mid]!=pre[preLeft])
mid++;
CreateBTreeHelp(r->leftChild,pre,in,preLeft+,preLeft+mid-inLeft,inLeft,mid-); //这里如果不懂建议自己画图手工实现一遍。
CreateBTreeHelp(r->rightChild,pre,in,preLeft+mid-inLeft+,preRight,mid+,inRight);
}
} template<typename ElemType>
//构造树
BinaryTree_Thr<ElemType>& BinaryTree_Thr<ElemType>::CreateBTree(ElemType pre[],ElemType in[],int n)
{
BinTreeNode<ElemType> *r; //根
CreateBTreeHelp(r,pre,in,,n-,,n-);
//return BinaryTree<ElemType>(r);//,不能这么返回,Error:不应该返回局部变量的地址
*this = BinaryTree_Thr<ElemType>(r);
return *this;
} #include<queue>
template<typename ElemType>
void BinaryTree_Thr<ElemType>::LevelOrder(void (*visit) (const ElemType &))const
{ //队列实现
visit=print;
queue<BinTreeNode<ElemType> *> q;
BinTreeNode<ElemType> *t=root;
if(t!=NULL) q.push(t); //根非空,入队
while(!q.empty()) //队不空
{
t=q.front();
q.pop(); //出队
(*visit)(t->data); //一层一层进行遍历,无法理解还是自己画图实现一遍
if(t->leftChild)
q.push(t->leftChild); //遍历左孩子
if(t->rightChild)
q.push(t->rightChild); //遍历右孩子
} } //operator =
template<typename ElemType>
BinaryTree_Thr<ElemType> &BinaryTree_Thr<ElemType>::operator=(const BinaryTree_Thr<ElemType> &copy)
{
if(&copy!=this)
{
DestroyHelp(root);
root=CopyTreeHelp(copy.root);
}
return *this;
}

线索化二叉树的构建与先序,中序遍历(C++版)的更多相关文章

  1. 数据结构与算法---线索化二叉树(Threaded BinaryTree)

    先看一个问题 将数列 {1, 3, 6, 8, 10, 14  } 构建成一颗二叉树 问题分析: 当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 } 但是 6, 8 ...

  2. 后序线索化二叉树(Java版)

    前面介绍了前序线索化二叉树.中序线索化二叉树,本文将介绍后序线索化二叉树.之所以用单独的一篇文章来分析后序线索化二叉树,是因为后序线索化二叉树比前序.中序要复杂一些:另外在复习线索化二叉树的过程中,大 ...

  3. YTU 3026: 中序线索化二叉树

    原文链接:https://www.dreamwings.cn/ytu3026/2896.html 3026: 中序线索化二叉树 时间限制: 1 Sec  内存限制: 128 MB 提交: 9  解决: ...

  4. 图解中序遍历线索化二叉树,中序线索二叉树遍历,C\C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  5. 图解前序遍历线索化二叉树,前序线索二叉树遍历,C\C++描述

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  6. JAVA递归实现线索化二叉树

    JAVA递归实现线索化二叉树 基础理论 首先,二叉树递归遍历分为先序遍历.中序遍历和后序遍历. 先序遍历为:根节点+左子树+右子树 中序遍历为:左子树+根节点+右子树 后序遍历为:左子树+右子树+根节 ...

  7. C#数据结构-线索化二叉树

    为什么线索化二叉树? 对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上,否则我们只知道后续的左右子树.现在我们充分利用二叉树左右子树的空节点,分别指向当前节点的前驱.后继,便 ...

  8. 【IT笔试面试题整理】给定二叉树先序中序,建立二叉树的递归算法

    [试题描述]:  给定二叉树先序中序,建立二叉树的递归算法 其先序序列的第一个元素为根节点,接下来即为其左子树先序遍历序列,紧跟着是右子树先序遍历序列,固根节点已可从先序序列中分离.在中序序列中找到 ...

  9. 二叉树 遍历 先序 中序 后序 深度 广度 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

随机推荐

  1. thinkphp之获取客户端IP地址

    /** * 获取客户端IP地址 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 * @return mixed */ function get_cl ...

  2. css里面position:relative与position:absolute的区别

    position:absolute这个是绝对定位:是相对于浏览器的定位.比如:position:absolute:left:20px;top:80px; 这个容器始终位于距离浏览器左20px,距离浏览 ...

  3. 【Android Developers Training】 0. 序言:构建你的第一个应用

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  4. 【Android Developers Training】 51. 序言:打印内容

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. eclipse更改maven的本地路径和外部仓库地址

    背景 当前使用eclipse自带的maven碰到两个蛋疼的问题: maven在国内使用如果不进行FQ则会痛苦不堪如便秘. maven下载大量jar包导致某盘不够用,需要换大的分区. 因此为了解决这个问 ...

  6. 从栈不平衡问题 理解 calling convention

    最近在开发的过程中遇到了几个很诡异的问题,造成了栈不平衡从而导致程序崩溃. 经过几经排查发现是和调用规约(calling convention)相关的问题,特此分享出来. 首先,讲一下什么是调用规约. ...

  7. Java面试常考------------------------垃圾收集算法

    对于Java系学生而言,Java虚拟机中的垃圾收集算法是一个很重要的面试考点. 常用的垃圾收集算法主要可划分为以下三类: 1. 标记-清除算法 标记清除算法是一种比较简单的方法,直接标记内存中待回收的 ...

  8. 如何将md文件转换成带目录的html文件

    配置环境node 去官网下一个node安装包,下一步下一步: 由于现在的node都自带npm,直接 npm install i5ting_toc 这样安装好了i5ting_toc这个包, 进入你实现准 ...

  9. vue.js实现内部自定义指令和全局自定义指令------directive

    在Vue中,我们平时数据驱动视图时候,内部自带的指令有时候解决不了一些需求,这时候,Vue给我们一个很好用的东东 directive 这个单词是我们写自定义指令的关键字哦 之定义指令为我们提供了几个钩 ...

  10. gulp环境搭建

    简介: gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:它不仅对网站资源进行优化,而且在开发过程中很多重复的任务,他可以通过明确的工具自动完成,使用它我们不仅可以很愉快的编写代码 ...