本代码主要参考了大话数据结构的思想,由于其为c语言版,所以本人对其中一些函数进行了封装,并增加了一些新的功能。

  由于本代码的基本思想在大话数据结构书中已经说的很清楚了,所以此处就不再进行说明代码原理。

  并且,在每个函数的后面,都写了其作用,本人也尽可能地在必要的地方加了注释。并且为了省事,用了shared_ptr。

  写此代码的目的是为了让简单线索二叉树的代码更加规范一点(很多c代码都是用全局变量等不规范的形式)。此代码在vs2019上能执行,编译器需要支持c++11以上。

文章目录

  • 一、线索二叉树节点类~
  • 二、线索二叉树类~
  • 三、完整头文件~
  • 四、测试cpp~

一、线索二叉树节点类~

using std::cout;
using std::endl;
using std::shared_ptr;
using std::make_shared;namespace {enum  class PointerTag{Linked, Thread};
}template<typename T = int>
struct ThreadNode {public:using ThreadNodePtr = shared_ptr<ThreadNode<T>>;public:T _data;ThreadNodePtr _lchild;ThreadNodePtr _rchild;PointerTag _lTag;/*左右标签*/PointerTag _rTag;ThreadNode(const T& data) :_data(data),_lchild(nullptr),_rchild(nullptr),_lTag(PointerTag::Linked),_rTag(PointerTag::Linked) {}ThreadNode(const ThreadNode& other):_data(other._data),_lchild(other._lchild),_rchild(other._rchild),_lTag(other._lTag),_rTag(other._rTag){}
};

二、线索二叉树类~

 template<typename T = int>class ThreadTree {public:using ThreadNodePtr = shared_ptr<ThreadNode<T>>;private:ThreadNodePtr _root;/*根节点*/ThreadNodePtr  _hot;//刚被访问过的节点ThreadNodePtr _head;//线索二叉树头节点哨兵public:ThreadTree() :_root(nullptr), _hot(nullptr), _head(nullptr) {}ThreadTree(T* PrevOrder, T* InOrder, const int& num) :_hot(nullptr), _head(nullptr) {//以前序和中序序列创建二叉树_root = buildTree(PrevOrder, InOrder, num);}void InThread();//从根节点开始,线索化二叉树void InOrderTrav_Thread()const;//以线索二叉树的方式进行遍历private:ThreadNodePtr buildTree(T* PrevOrder, T* InOrder, const int& num);//以前序和中序序列创建二叉树void InThreading(ThreadNodePtr); /*对根节点进行中序线索化*/};

三、完整头文件~

#pragma once
using std::cout;
using std::endl;
using std::shared_ptr;
using std::make_shared;namespace my_thread_tree {namespace {enum  class PointerTag{Linked, Thread};}template<typename T = int>struct ThreadNode {public:using ThreadNodePtr = shared_ptr<ThreadNode<T>>;public:T _data;ThreadNodePtr _lchild;ThreadNodePtr _rchild;PointerTag _lTag;/*左右标签*/PointerTag _rTag;ThreadNode(const T& data) :_data(data),_lchild(nullptr),_rchild(nullptr),_lTag(PointerTag::Linked),_rTag(PointerTag::Linked) {}ThreadNode(const ThreadNode& other):_data(other._data),_lchild(other._lchild),_rchild(other._rchild),_lTag(other._lTag),_rTag(other._rTag){}};template<typename T = int>class ThreadTree {public:using ThreadNodePtr = shared_ptr<ThreadNode<T>>;private:ThreadNodePtr _root;/*根节点*/ThreadNodePtr  _hot;//刚被访问过的节点ThreadNodePtr _head;//线索二叉树头节点哨兵public:ThreadTree() :_root(nullptr), _hot(nullptr), _head(nullptr) {}ThreadTree(T* PrevOrder, T* InOrder, const int& num) :_hot(nullptr), _head(nullptr) {//以前序和中序序列创建二叉树_root = buildTree(PrevOrder, InOrder, num);}void InThread();//从根节点开始,线索化二叉树void InOrderTrav_Thread()const;//以线索二叉树的方式进行遍历private:ThreadNodePtr buildTree(T* PrevOrder, T* InOrder, const int& num);//以前序和中序序列创建二叉树void InThreading(ThreadNodePtr);   /*对根节点进行中序线索化*/};template<typename T>void ThreadTree<T>::InOrderTrav_Thread()const{ThreadNodePtr p = _root;//指向根节点while (p != _head) {//当没有遍历到头节点哨兵时while (p->_lTag == PointerTag::Linked)//一直往左,直到左孩子记录的为前驱而不是左孩子时p = p->_lchild;cout << "数据为:\t" << p->_data << "\t引用计数为:\t" << p.use_count() << endl;while (p->_rTag == PointerTag::Thread && p->_rchild != _head) {//遍历到直到p的右孩子为右孩子而不是后继时p = p->_rchild;cout << "数据为:\t" << p->_data << "\t引用计数为:\t" << p.use_count() << endl;}p = p->_rchild;//p进入右子树根}cout << endl;}template<typename T>shared_ptr<ThreadNode<T>>  ThreadTree<T>::buildTree(T* PrevOrder, T* InOrder, const int& num){if (PrevOrder == nullptr || InOrder == nullptr || num <= 0){return nullptr;}ThreadNodePtr root =make_shared<ThreadNode<T>>(PrevOrder[0]);// 前序遍历的第一个数据就是根节点数据    //中序遍历,根节点左为左子树,右为右子树    int rootposition = -1;for (int i = 0; i < num; i++){if (InOrder[i] == root->_data){rootposition = i;}}if (rootposition == -1)return nullptr;//重建左子树(根节点)递归    int LeftNum = rootposition;T* PrevOrderLeft = PrevOrder + 1; //前序第二个即为根节点的左子树    T* InOrderLeft = InOrder; //中序第一个 即为其左子树。    root->_lchild = buildTree(PrevOrderLeft, InOrderLeft, LeftNum);//重建右子树(根节点)递归    int RightNum = num - LeftNum - 1;//右半边子树T* PrevOrderRight = PrevOrder + 1 + LeftNum;T* InOrderRight = InOrder + LeftNum + 1;root->_rchild = buildTree(PrevOrderRight, InOrderRight, RightNum);return root;}template<typename T>void ThreadTree<T>::InThreading(ThreadNodePtr p){if (p != nullptr) {InThreading(p->_lchild);if (p->_lchild == nullptr) {p->_lTag = PointerTag::Thread;p->_lchild = _hot;//p的左孩子设为前驱}if (_hot != nullptr && _hot->_rchild == nullptr) {//前驱的右孩子为空时_hot->_rTag = PointerTag::Thread;_hot->_rchild = p;//将前驱的右孩子设为p}_hot = p;InThreading(p->_rchild);}}template<typename T>void ThreadTree<T>::InThread() {//从根节点开始,线索化二叉树if (_root == nullptr)return;//头哨兵节点初始化_head = make_shared<ThreadNode<T>>(0);//反正不会访问这个,所以初值不妨就设成0_head->_rTag = PointerTag::Thread;_head->_lchild = _root;_head->_rchild = _head;_hot = _head;//将_hot设定为_headInThreading(_root);//线索化二叉树//遍历之后,_hot必然为中序遍历最右边那个节点_hot->_rTag = PointerTag::Thread;_hot->_rchild = _head;//就将头哨兵作为_hot的右孩子_head->_rchild = _hot;//并且将_hot作为头哨兵的右孩子}}//namespace my_thread_tree

四、测试cpp~

#include <iostream>
#include "ThreadTree.h"
using namespace std;
using namespace my_thread_tree;int main() {//int a[] = { 3,1,0,2,5,4,6 };//int b[] = { 0,1,2,3,4,5,6 };char a[] = { 'A','B','D','H','I','E','J','C','F','G'};char b[] = { 'H','D','I','B','J','E','A','F','C','G' };ThreadTree<char> TT(a, b, 10);//传参时传入两个数组,分别为树的前序和中序遍历序列TT.InThread();TT.InOrderTrav_Thread();return 0;
}

引用计数这个可以忽略,主要是玩下看有多少个指针指向这个对象

数据为: H       引用计数为:     2
数据为: D       引用计数为:     4
数据为: I       引用计数为:     2
数据为: B       引用计数为:     4
数据为: J       引用计数为:     2
数据为: E       引用计数为:     3
数据为: A       引用计数为:     5
数据为: F       引用计数为:     2
数据为: C       引用计数为:     4
数据为: G       引用计数为:     4

c++ 实现线索二叉树相关推荐

  1. 数据结构与算法(6-4)线索二叉树

    优势:便于在中序遍历下,查找前驱和后继. 前驱/后继含义:AB中,A是B前驱,B是A后继. ltag=0时:lchild指向左孩子                ltag=1时:lchild指向前驱 ...

  2. 重拾算法(3)——用458329个测试用例全面测试二叉树和线索二叉树的遍历算法

    重拾算法(3)--用458329个测试用例全面测试二叉树和线索二叉树的遍历算法 在"上一篇"和"上上一篇"中,我给出了二叉树和线索二叉树的遍历算法.给出算法容易 ...

  3. 线索二叉树代码实现 - 数据结构和算法49

    线索二叉树代码实现 让编程改变世界 Change the world by program   程序参考代码:http://bbs.fishc.com/forum-112-1.html [buy] 获 ...

  4. 线索二叉树(c/c++)

    线索二叉树 定义: 对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树. 特 ...

  5. 【线索二叉树详解】数据结构06(java实现)

    线索二叉树 1. 线索二叉树简介 定义: 在二叉树的结点上加上线索的二叉树称为线索二叉树. 二叉树的线索化: 对二叉树以某种遍历方式(如先序.中序.后序或层次等)进行遍历,使其变为线索二叉树的过程称为 ...

  6. 线索二叉树原理及前序、中序线索化(Java版)

    转载 原文地址:https://blog.csdn.net/UncleMing5371/article/details/54176252 一.线索二叉树原理 前面介绍二叉树原理及特殊二叉树文章中提到, ...

  7. 【数据结构-树】2.二叉树遍历与线索二叉树(图解+代码)

    一.二叉树的定义及其主要特征 1.1 二叉树的概念 二叉树是另一种树形结构,其特点是每个结点最多含两棵子树(也就是说,二叉树的度≤2). 二叉树是一种有序树,若将其左.右子树颠倒,则成为另一颗不同的二 ...

  8. 为什么说线索二叉树是一种物理结构

    1 数据结构三要素中的两个要素分别为 数据的逻辑结构 数据的存储结构,也称物理结构 它们的精确定义是: 数据的逻辑结构 数据元素之间的逻辑关系,与数据的存储无关. 数据的存储结构 数据结构在计算机中的 ...

  9. 线索二叉树(基于链表存储树结点)

    有以下场景 如果使用中序遍历,那么得到的顺序是:HDIBEAFCG,可以得知A的前驱结点为E,后继结点为F.但是,这种关系的获得是建立在完成遍历后得到的.如果我们每次想得到某个节点的前驱或者后继,都要 ...

  10. 我这么讲线索二叉树,我三岁大的表弟笑了笑

    目录: 1.线索二叉树的由来 2.线索二叉树的概念和结构 3.二叉树的线索化 4.中序线索二叉树的代码实现 5.遍历线索二叉树 1.线索二叉树的由来 我问表弟下面的一个问题: 在n个结点一个二叉链表中 ...

最新文章

  1. php 回复id同过session 任意获取id不通过a,PHP会话ID相同但变量丢失
  2. 这几种Java异常处理方法,你会吗?
  3. jqGrid文字根据表格大小自动换行
  4. android studio代码对齐的快捷键
  5. flutter打包的app有多大_Flutter原生混合开发
  6. 基于surging 的stage组件设计,谈谈我眼中的微服务
  7. 谈谈对于技术面试的心得体验
  8. 卡耐基梅隆计算机学院,卡内基梅隆计算机学院--计算机系简介
  9. 网页获取服务器时间,通过AFNetworking获取服务器时间
  10. css tab 后竖线_H5网页布局+css代码美化,零基础参考
  11. Mysql字段修饰符(约束)
  12. java 过滤器(参数传递中文乱码)
  13. Java Code Examples for org.apache.ibatis.annotations.Insert
  14. python画3d图-使用python绘制3d的图形
  15. xsd文件转图片_原来华为手机能一键将图片转为PDF,实在太方便啦!你还不会吗?...
  16. 用Bat脚本写一个无限弹窗代码
  17. 深度分析:PSP3000被破解 狂欢?还是哀悼?
  18. 电脑长截图的操作方法
  19. photoshop插画插件_照片快速转矢量插画PS动作插件 Vector Art Photoshop Action
  20. httpClient发送post请求,带header、body的工具类

热门文章

  1. 电脑 耳机播放声音,左右耳朵不平衡解决方法
  2. Listener refused the connection with the following error: ORA-12519, TNS:no appr
  3. 技术宅---我的网上抢火车票攻略
  4. [Python面试][基础算法题]Python基础面试(基础算法题目较多)
  5. 怎样将本地图片转换成网络链接图片
  6. Java,完全一头雾水,求大shen们指点
  7. 马云谈“大数据”:很多人对这三个字有误解
  8. 【Unity教程】如何动态更换精灵图片在图集中更换精灵图片
  9. html5 指南针,html5指南针实现
  10. linux引导记录重新安装