body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

对于一个有n个结点的二叉链表,每个结点有指向左右孩子的两个指针域,所以一共是2n个指针域,而n个结点的二叉树一共有n-1条分支线路,也就是说,存在2n-(n-1)= n+1个空指针域。
考虑利用那些空地址,存放指向结点在某种遍历次序下的前驱和后继结点的地址。  我们把这种指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树(Threaded Binary Tree)
对二叉树进行中序遍历后,将所有空指针域中的rchild改为指向它们的后继结点。
  ① H的后继是D
   ...
  ⑥ G的后继是NULL,中序遍历最后一个节点
此时共有6个空指针域被利用
将所有空指针域中的lchild改为指向当前节点的前驱。
  ① H的前驱是NULL,中序遍历的第一个结点
   ...
  ⑥ G的前驱是C
此时共有5个空指针被利用
最终,空心箭头实线为前驱,虚线黑箭头为后继。线索二叉树,等于是把一棵二叉树变成了一个双向链表,这样插入一个结点、查找一个结点都很方便。对二叉树以某种次序遍历使其变为线索二叉树的过程称为是线索化
为了区分lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继,需要用一个标志位来区分
■ ltag为0时指向该结点的左孩子,为1时指向该结点的前驱
■ rtag为0时指向该结点的右孩子,为1时指向该结点的后继

二叉树输入过程:ABDH##I##EJ###CF##G## 中序遍历:HDIBJEAFCG
中序遍历: bac 中序遍历:CBAEDF
#include<iostream>
using namespace std;
enum TBT{child=0,thread};  //线索二叉树结点的指针是指向孩子还是前驱后继
typedef struct tbt
{
        struct tbt* lchild;
        enum TBT ltag;
        char data;
        enum TBT rtag;
        struct tbt* rchild;
}TBTreeNode,*pTBTree;
int createThreadedBinaryTree(pTBTree& root);
void inorderThreadingBinaryTree(const pTBTree& root);  //中序线索化二叉树
//在中序遍历的同时就线索化二叉树
void inorderThreadedBinaryTreeTraversal(pTBTree root); //中序线索化二叉树遍历
int main()
{
        TBTreeNode* root = nullptr;
        int ret = createThreadedBinaryTree(root);
        {
                if(0==ret)
                {
                        inorderThreadingBinaryTree(root);
                        cout<<endl;
                        inorderThreadingBinaryTreeTraversal(root);
                        cout<<endl;
                }
        }
        system("pause");
}
int createThreadedBinaryTree(pTBTree& root)
{
        char data;
        if(cin>>data)
        {
                if('#'==data)
                {
                        root = nullptr;
                        return -1;
                }
                else
                { //用data数据来初始化root结点,然后递归建立左子树和右子树
                        root = new TBTreeNode();  //创建结点的时候就把结点全部赋值为空
                        root->data = data;
                        createThreadedBinaryTree(root->lchild);
                        createThreadedBinaryTree(root->rchild);
                }
        }
        return 0;
}
static TBTreeNode* pre = nullptr;  //定义一个指针指向中序遍历当前访问结点的前一个访问结点
//线索化结点的后继要用到,因为中序遍历顺序:左子树,根结点,右子树
//前驱可以用刚刚访问过的结点直接赋值,后继还没有访问,这时候当前结点就是上一个访问结点pre的后继
//当然,前提条件是pre的右子树为空
//pre初始值为nullptr,因为从根结点开始访问,前一个访问结点就只能是空了
void inorderThreadingBinaryTree(const pTBTree& root)
{
        if(nullptr==root)
                return ;
        /*  参考中序遍历
        inorderTraversal(root->lchild);
        cout<<root->data<<" ";
        inorderTraversal(root->rchild);
        */
        inorderThreadingBinaryTree(root->lchild);  //中序遍历左子树
        //判断结点指针域可不可以线索化
        if(nullptr==root->lchild)  //如果左子树为空,就可以把指针域拿来线索化,指向前驱
        {
                root->lchild = pre;
                root->ltag = thread;
        }
        if(nullptr!=pre&&nullptr==pre->rchild)  //如果当前访问的根结点不为空,并且前面访问的结点pre右子树为空,线索化前一个结点的后继
        {
                pre->rchild = root;
                pre->rtag = thread;
        }
        //访问根结点就变成修改前一个访问结点指针pre
        pre = root;  //之后要访问右子树,当前结点自然就是pre
        inorderThreadingBinaryTree(root->rchild);  //中序遍历右子树
}
void inorderThreadedBinaryTreeTraversal(pTBTree root)
{
        if(nullptr==root)
                return;
        while(nullptr!=root)
        {
                while(nullptr!=root->lchild&&child==root->ltag)  //两个条件,区别中序遍历第一个结点的前驱是nullptr
                {//搜寻从根结点开始的左子树的最后一个节点
                        root = root->lchild;
                }
                cout<<root->data<<" ";  //输出根结点
                while(thread==root->rtag)  //该结点有后继,意味着没有右子树
                {
                        cout<<root->rchild->data<<" ";  //直接输出后继,也就是中序遍历当前结点下一个要访问的结点的值
                        root = root->rchild;  //根结点回溯到后继
                }
                //该结点有右子树,root->rtag==child,左子树已经遍历完了,这里进入右子树
                root = root->rchild;  //重复上面的操作
        }
}

图解中序遍历线索化二叉树,中序线索二叉树遍历,C\C++描述的更多相关文章

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

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

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

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

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

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

  4. 线索化二叉树的构建与先序,中序遍历(C++版)

    贴出学习C++数据结构线索化二叉树的过程, 方便和我一样的新手进行测试和学习 同时欢迎各位大神纠正. 不同与普通二叉树的地方会用背景色填充 //BinTreeNode_Thr.h enum Point ...

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

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

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

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

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

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

  8. 【算法】二叉树、N叉树先序、中序、后序、BFS、DFS遍历的递归和迭代实现记录(Java版)

    本文总结了刷LeetCode过程中,有关树的遍历的相关代码实现,包括了二叉树.N叉树先序.中序.后序.BFS.DFS遍历的递归和迭代实现.这也是解决树的遍历问题的固定套路. 一.二叉树的先序.中序.后 ...

  9. 算法进阶面试题03——构造数组的MaxTree、最大子矩阵的大小、2017京东环形烽火台问题、介绍Morris遍历并实现前序/中序/后序

    接着第二课的内容和带点第三课的内容. (回顾)准备一个栈,从大到小排列,具体参考上一课.... 构造数组的MaxTree [题目] 定义二叉树如下: public class Node{ public ...

随机推荐

  1. windows下vue开发环境的搭建

    一 介绍: vue.js是什么? Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的渐进式框架.与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计.Vue 的核心库 ...

  2. GROUP by 方法  C#

    1.用两层循环计算,前提条件是数据已经按分组的列排好序的. DataTable dt = new DataTable(); dt.Columns.AddRange(new DataColumn[] { ...

  3. Introduction to dnorm, pnorm, qnorm, and rnorm for new biostatisticians

    原文:Introduction todnorm,pnorm,qnorm, andrnormfor new biostatisticians Today I was in Dan’s office ho ...

  4. 使用jquery-form进行文件上传

    jquery.form.js是一个form插件,支持ajax表单提交和ajax上传. 使用时,需要在代码中添加如下: <script src="http://malsup.github ...

  5. linux权限管理之文件属性

    文件属性 chattr ======================================================== 文件权限管理之: 文件属性注:设置文件属性(权限),针对所有用 ...

  6. 20181013xlVba计算优秀率及合格率

    Sub 计算高一优秀合格率() Dim Wb As Workbook Dim Sht As Worksheet Dim oSht As Worksheet Dim dOs As Object 'Out ...

  7. position属性的总结

    static 默认.位置设置为 static 的元素,它始终会处于页面流给予的位置(static 元素会忽略任何 top.bottom.left 或 right 声明). relative 位置被设置 ...

  8. Android之Activity生命周期详解

    Activity的生命周期方法: onCreate()--->onStart()--->onResume()--->onPause()--->onStop()--->on ...

  9. 把url链接转换成二维码的工具类

    import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io ...

  10. [luogu P3275] [SCOI2011]糖果

    [luogu P3275] [SCOI2011]糖果 题目描述 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些 ...