》》如何用C语言构建一颗二叉树?

第一种方法:

ThreadTree A = (ThreadTree)malloc(sizeof(ThreadNode));A->data = { 'A' };A->ltag = 0;A->rtag = 0;A->lchild = NULL;A->rchild = NULL;ThreadTree B = (ThreadTree)malloc(sizeof(ThreadNode));B->data = { 'B' };A->lchild = B;B->ltag = 0;B->rtag = 0;B->lchild = NULL;B->rchild = NULL;ThreadTree C = (ThreadTree)malloc(sizeof(ThreadNode));C->data = { 'C' };A->rchild = C;C->lchild = NULL;C->rchild = NULL;C->ltag = 0;C->rtag = 0;ThreadTree D = (ThreadTree)malloc(sizeof(ThreadNode));D->data = { 'D' };B->lchild = D;D->lchild = NULL;D->rchild = NULL;D->ltag = 0;D->rtag = 0;ThreadTree E = (ThreadTree)malloc(sizeof(ThreadNode));E->data = { 'E' };B->rchild = E;E->lchild = NULL;E->rchild = NULL;E->ltag = 0;E->rtag = 0;ThreadTree F = (ThreadTree)malloc(sizeof(ThreadNode));F->data = { 'F' };C->lchild = F;F->lchild = NULL;F->rchild = NULL;F->ltag = 0;F->rtag = 0;ThreadTree G = (ThreadTree)malloc(sizeof(ThreadNode));G->data = { 'G' };D->rchild = G;G->lchild = NULL;G->rchild = NULL;G->ltag = 0;G->rtag = 0;

第二种方法:

》》了解为什么要利用线索的先前知识

关键:n个结点的二叉树,有n+1个空链域!可用来记录前驱、后继的信息

》》线索二叉树的存储结构

》》中序线索二叉树

  • 前驱线索(由左孩子指针充当)
  • 后继线索(由右孩子指针充当)

》》中序线索二叉树的存储

》》中序线索化

》》中序线索二叉树找中序后继

》》中序线索二叉树找中序前驱

》》完整代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;typedef int ElemType;
//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
}ThreadNode, * ThreadTree;//创建二叉树
ThreadNode* Create(ThreadNode* bt) {static int i = 0;char ch;//string str = "AB#D##C##";string str = "ABD#G##E##CF###";ch = str[i++];if (ch == '#')bt = NULL;//建立一棵空树 else {bt = (ThreadTree)malloc(sizeof(ThreadNode)); bt->data = ch;//生成一个结点,数据域为chbt->lchild = Create(bt->lchild);//递归建立左子树bt->rchild = Create(bt->rchild);//递归建立右子树bt->ltag = 0; bt->rtag = 0;}return bt;
}//中序遍历
void OrdinaryInOrder(ThreadNode* T) {if (T != NULL) {OrdinaryInOrder(T->lchild);//中序遍历左子树printf("%c ", T->data);//访问根节点的数据域OrdinaryInOrder(T->rchild);//中序遍历右子树}
}//中序线索化
void InThread(ThreadTree p,ThreadTree &pre) {if (p != NULL) {InThread(p->lchild,pre);//递归,线索化左子树if (p->lchild == NULL) {//左子树为空,建立前驱线索p->lchild = pre;p->ltag = 1;}if (pre != NULL && pre->rchild == NULL) {pre->rchild = p;//建立前驱结点的后继线索pre->rtag = 1;}pre = p;InThread(p->rchild,pre);//中序遍历右子树}
}//中序线索化二叉树
void CreateInThread(ThreadTree T) {ThreadTree pre = NULL;//pre 初始为NULLif (T != NULL) {//非空二叉树才能线索化InThread(T,pre);//中序线索化二叉树pre->rchild = NULL;//处理遍历的最后一个结点pre->rtag = 1;}
}/*在中序线索二叉树中找到指定结点 *p的中序后继next①若p->rtag == 1,则next = p->rchild②p->rtag == 0(p必定有右孩子)中序遍历--左    根      右左    根    (左 根 右)左    根  ((左 根 右) 根 右)
*/
//找到以P为根的子树中,第一个被中序遍历的结点
ThreadNode* FirstNode(ThreadNode* p) {//循环找到最左下结点(不一定是叶结点)while (p->ltag == 0)p = p->lchild;return p;
}
//在中序线索二叉树中找到结点p的后继结点
ThreadNode* NextNode(ThreadNode* p) {//右子树中最左下结点if (p->rtag == 0)return FirstNode(p->rchild);elsereturn p->rchild;//rtag==1直接返回后继线索
}//中序线索二叉树的中序遍历
void InOrder(ThreadNode* T) {for (ThreadNode* p = FirstNode(T); p != NULL; p = NextNode(p)) {printf("%c ", p->data);//访问根节点的数据域}printf("\n");
}/*在中序线索二叉树中找到指定结点*p的中序前驱pre①若p->ltag == 1,则pre = p->lchild;②若p->ltag == 0(必有左孩子)中序遍历--左                      根      右(左 根 右)              根      右((左 根 右) 根 右)      根      右
*///找到以P为根的子树中,最后一个被中序遍历的结点
ThreadNode* LastNode(ThreadNode* p) {//循环找到最右下结点(不一定是叶结点)while (p->rtag == 0)p = p->rchild;return p;
}//在中序线索二叉树中找到结点p的前驱结点
ThreadNode* PreNode(ThreadNode* p) {//左子树中最右下结点if (p->ltag == 0)return LastNode(p->lchild);else return p->lchild;//ltag == 1直接返回前驱线索
}//对中序线索二叉树进行逆向中序遍历
void RevInOrder(ThreadNode* T) {for (ThreadNode* p = LastNode(T); p != NULL; p = PreNode(p)) {printf("%c ", p->data);//访问根节点的数据域}printf("\n");
}//寻找指定值的结点
ThreadNode* findNode(ThreadTree t, int NodeData) {if (t == NULL) {return NULL;}if (t->data == NodeData) {return t;}ThreadNode* p;for (p = FirstNode(t); p != NULL; p = NextNode(p)) {if (p->data == NodeData) {return p;}}return NULL;
}//思考:处理遍历的最后一个结点时,为什么没有判断rchild是否为NULL?
//答案:中序遍历的最后一个结点右孩子指针必为空int main() {ThreadNode* p = (ThreadTree)malloc(sizeof(ThreadNode)); //记录目标节点p->data = 'C';//p指向目标结点//创建一棵二叉树ThreadTree T = (ThreadTree)malloc(sizeof(ThreadNode));//创建一颗二叉树T = Create(T);printf("---普通中序遍历--- \n");//B D A COrdinaryInOrder(T);printf("\n");CreateInThread(T);printf("---中序线索二叉树找后继的中序遍历--- \n");//B D A CInOrder(T);printf("---中序线索二叉树找前驱的逆向的中序遍历--- \n");//B D A CRevInOrder(T);//printf("%c \n", findNode(T, p->data)->data);ThreadTree findCurrentNode = (ThreadTree)malloc(sizeof(ThreadNode));findCurrentNode = findNode(T, p->data);if (NextNode(findCurrentNode) != NULL) {printf("%c的后继是:%c", findCurrentNode->data, NextNode(findCurrentNode)->data);}else {printf("%c没有后继了", findCurrentNode->data);}printf("\n");if (PreNode(findCurrentNode) != NULL) {printf("%c的前驱是:%c", findCurrentNode->data, PreNode(findCurrentNode)->data);}else {printf("%c没有前驱了", findCurrentNode->data);}printf("\n");return 0;
}

》》实验效果

》》先序线索二叉树

》》先序线索二叉树的存储

》》先序线索化(需要解决“转圈问题”)

》》先序线索二叉树找先序后继

》》先序线索二叉树找先序前驱

》》总结

》》先序线索二叉树找先序后继

》》完整代码

#include<iostream>
#include<stdio.h>
#include <stdlib.h>#include<string.h>
using namespace std;typedef int ElemType;
//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
}ThreadNode, * ThreadTree;//创建二叉树
ThreadNode* Create(ThreadNode* bt) {static int i = 0;char ch;//string str = "AB#D##C##";string str = "ABD#G##E##CF###";ch = str[i++];if (ch == '#')bt = NULL;//建立一棵空树 else {bt = (ThreadTree)malloc(sizeof(ThreadNode)); bt->data = ch;//生成一个结点,数据域为chbt->ltag = 0; bt->rtag = 0;bt->lchild = Create(bt->lchild);//递归建立左子树bt->rchild = Create(bt->rchild);//递归建立右子树}return bt;
}//先序遍历
void OrdinaryPreOrder(ThreadNode* T) {if (T != NULL) {printf("%c ", T->data);//访问根节点的数据域OrdinaryPreOrder(T->lchild);//先序遍历左子树OrdinaryPreOrder(T->rchild);//先序遍历右子树}
}//先序线索化
void PreThread(ThreadTree p, ThreadTree& pre) {if (p != NULL) {if (p->lchild == NULL) {//左子树为空,建立前驱线索p->lchild = pre;p->ltag = 1;}if (pre != NULL && pre->rchild == NULL) {pre->rchild = p;//建立前驱结点的后继线索pre->rtag = 1;}pre = p;//printf("%c", p->data);if (p->ltag == 0) {PreThread(p->lchild, pre);//递归,线索化左子树}    if (p->rtag == 0) {PreThread(p->rchild, pre);}}
}//先序线索化二叉树T
void CreatePreThread(ThreadTree& T) {ThreadTree pre = NULL;//pre 初始为NULLif (T != NULL) {//非空二叉树才能线索化PreThread(T, pre);//先序线索化二叉树if(pre->rchild == NULL)pre->rtag = 1;}
}/*在先序线索二叉树中找到指定结点*p的先序后继(next)①若p->rtag == 1,则 next = p->rchild②若p->rtag == 0》》若p有左孩子,则先序后继为左孩子先序遍历---- 根           左            右根         (根 左 右)    右》》若p没有左孩子,则先序后继为右孩子先序遍历---- 根           右根         (根 左 右)先序线索二叉树能否找到先序前驱呢?(提示:【先序遍历:根左右】)答:不能,因为在左右子树中的结点只可能是根的后继,不可能是前驱。*/
//在先序线索二叉树中找到结点p的后继结点
ThreadNode* NextNode(ThreadNode* p) {if (p->rtag == 1) {return p->rchild;}else {if (p->ltag == 0)  //若p有左孩子,则先序后继为左孩子return p->lchild;else//若p没有左孩子,则先序后继为右孩子return p->rchild;}
}//先序线索二叉树先序遍历
void PreOrder(ThreadTree T) {for (ThreadNode* p = T; p != NULL; p = NextNode(p)) {printf("%c ", p->data);//访问根节点的数据域}printf("\n");
}//寻找指定值的结点
ThreadNode* findNode(ThreadTree T, int NodeData) {if (T == NULL) {return NULL;}if (T->data == NodeData) {return T;}ThreadNode* p;for (p = T; p != NULL; p = NextNode(p)) {if (p->data == NodeData) {return p;}}return NULL;
}int main() {ThreadNode* p = (ThreadTree)malloc(sizeof(ThreadNode)); //记录目标节点p->data = 'C';//p指向目标结点//创建一棵二叉树ThreadTree T = (ThreadTree)malloc(sizeof(ThreadNode));//创建一颗二叉树T = Create(T);/*ThreadTree A = (ThreadTree)malloc(sizeof(ThreadNode));A->data = { 'A' };A->ltag = 0;A->rtag = 0;A->lchild = NULL;A->rchild = NULL;ThreadTree B = (ThreadTree)malloc(sizeof(ThreadNode));B->data = { 'B' };A->lchild = B;B->ltag = 0;B->rtag = 0;B->lchild = NULL;B->rchild = NULL;ThreadTree C = (ThreadTree)malloc(sizeof(ThreadNode));C->data = { 'C' };A->rchild = C;C->lchild = NULL;C->rchild = NULL;C->ltag = 0;C->rtag = 0;ThreadTree D = (ThreadTree)malloc(sizeof(ThreadNode));D->data = { 'D' };B->lchild = D;D->lchild = NULL;D->rchild = NULL;D->ltag = 0;D->rtag = 0;ThreadTree E = (ThreadTree)malloc(sizeof(ThreadNode));E->data = { 'E' };B->rchild = E;E->lchild = NULL;E->rchild = NULL;E->ltag = 0;E->rtag = 0;ThreadTree F = (ThreadTree)malloc(sizeof(ThreadNode));F->data = { 'F' };C->lchild = F;F->lchild = NULL;F->rchild = NULL;F->ltag = 0;F->rtag = 0;ThreadTree G = (ThreadTree)malloc(sizeof(ThreadNode));G->data = { 'G' };D->rchild = G;G->lchild = NULL;G->rchild = NULL;G->ltag = 0;G->rtag = 0;*/printf("---普通先序遍历--- \n");OrdinaryPreOrder(T);printf("\n");//创建先序线索二叉树CreatePreThread(T);printf("---先序线索二叉树找后继的先序遍历--- \n");PreOrder(T);printf("\n");//寻找结点ThreadTree findCurrentNode = (ThreadTree)malloc(sizeof(ThreadNode));findCurrentNode = findNode(T, p->data);//寻找结点的后继结点if (NextNode(findCurrentNode) != NULL) {printf("%c 的后继是:%c", findCurrentNode->data, NextNode(findCurrentNode)->data);}else {printf("%c 没有后继了", findCurrentNode->data);}printf("\n");return 0;
}

》》实验结果

》》后序线索二叉树

》》后序线索二叉树的存储

》》后序线索化

王道的后序线索化,处理遍历的最后一个结点让pre->rchild = NULL,pre->rtag=1;

但好像可以省去这一步。(仅个人看法,因为去掉之后运行也是正常的,如有错误,欢迎指正!!!) 

》》后序线索二叉树找后序后继

 》》后序线索二叉树找后序前驱

》》总结 

》》后序线索二叉树找后序前驱

 》》完整代码

#include<iostream>
#include<stdio.h>
#include <stdlib.h>#include<string.h>
using namespace std;typedef int ElemType;
//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
}ThreadNode, * ThreadTree;ThreadNode* Create(ThreadNode* bt) {static int i = 0;char ch;//string str = "AB#D##C##";string str = "ABD#G##E##CF###";ch = str[i++];if (ch == '#')bt = NULL;//建立一棵空树 else {bt = (ThreadTree)malloc(sizeof(ThreadNode)); bt->data = ch;//生成一个结点,数据域为chbt->ltag = 0; bt->rtag = 0;bt->lchild = Create(bt->lchild);//递归建立左子树bt->rchild = Create(bt->rchild);//递归建立右子树}return bt;
}//后序遍历
void OrdinaryPostOrder(ThreadNode* T) {if (T != NULL) {OrdinaryPostOrder(T->lchild);//后序遍历左子树OrdinaryPostOrder(T->rchild);//后序遍历右子树printf("%c ", T->data);//访问根节点的数据域}
}//后序线索化
void PostThread(ThreadTree p, ThreadTree& pre) {if (p != NULL) {PostThread(p->lchild, pre);//递归,线索化左子树PostThread(p->rchild, pre);//递归,线索化右子树if (p->lchild == NULL) {//左子树为空,建立前驱线索p->lchild = pre;p->ltag = 1;}if (pre != NULL && pre->rchild == NULL) {pre->rchild = p;//建立前驱结点的后继线索pre->rtag = 1;}pre = p;//标记当前结点成为刚刚访问的结点}
}//后序线索化二叉树
void CreatePostThread(ThreadTree T) {ThreadTree pre = NULL;if (T != NULL) {//非空二叉树才能线索化PostThread(T, pre);//线索化二叉树if(pre->rchild == NULL)//处理遍历的最后一个结点pre->rtag = 1;}
}/*在后序线索二叉树中找到指定结点*p的后序前驱(pre)①若p->ltag == 1,则 pre = p->lchild②若p->ltag == 0》》若p有右孩子,则后序前驱为右孩子先序遍历---- 左            右            根左    (左 右 根)          根》》若p没有右孩子,则后序前驱为左孩子先序遍历---- 左            根(左 右 根)    根后序线索二叉树能否找到后序后继呢?(提示:【后序遍历:左右根】)答:不能,因为在左右子树中的结点只可能是根的前驱,不可能是后继。
*/
//在后序线索二叉树中找到结点p的前驱结点
ThreadNode* PreNode(ThreadNode* p) {if (p->ltag == 1)return p->lchild;else {if (p->rtag == 0) {return p->rchild;}else {return p->lchild;}}
}void RevPostOrder(ThreadTree T) {for (ThreadNode* p = T; p != NULL; p = PreNode(p)) {printf("%c ", p->data);//访问根节点的数据域}printf("\n");
}//寻找指定值的结点
ThreadNode* findNode(ThreadTree T, int NodeData) {if (T == NULL) {return NULL;}if (T->data == NodeData) {return T;}ThreadNode* p;for (p = T; p != NULL; p = PreNode(p)) {if (p->data == NodeData) {return p;}}return NULL;
}int main() {ThreadNode* p = (ThreadTree)malloc(sizeof(ThreadNode)); //记录目标节点p->data = 'A';//p指向目标结点//创建一棵二叉树ThreadTree T = (ThreadTree)malloc(sizeof(ThreadNode));//创建一颗二叉树T = Create(T);printf("---普通后序遍历--- \n");OrdinaryPostOrder(T);printf("\n");//创建后序线索二叉树CreatePostThread(T);printf("---后序线索二叉树找前驱的逆向的后序遍历--- \n");RevPostOrder(T);printf("\n");//寻找结点ThreadNode* findCurrentNode = (ThreadTree)malloc(sizeof(ThreadNode));findCurrentNode = findNode(T, p->data);if (PreNode(findCurrentNode) != NULL) {printf("%c的前驱是:%c", findCurrentNode->data, PreNode(findCurrentNode)->data);}else {printf("%c没有前驱了", findCurrentNode->data);}printf("\n");return 0;
}

》》实验结果

》》三种线索二叉树的对比

本文是根据王道考研的数据结构教学视频中,运用其分析原理思想,再结合自己的一些思路分析和逻辑编程,进行完整的代码的编写。如有不正确的地方,欢迎指正!

C语言实现线索化二叉树(先序、中序、后序)相关推荐

  1. 数据结构-线索化二叉树

    文章目录 1.什么是线索二叉树 2.中序线索化二叉树 2.1 中序线索化二叉树实现 2.2 中序线索化二叉树遍历实现 3.先序线索化二叉树 3.1 先序线索化二叉树实现 3.2 先序线索化二叉树遍历实 ...

  2. 【算法系列之线索化二叉树,前序线索化、中序线索化、后序线索化以及遍历~】

    1.何谓线索化二叉树 2.线索化二叉树的本质 3.线索化二叉树的存储结构 4.构建线索化二叉树 4.1.先序线索化 4.2.中序线索化 4.3.后序线索化 5.遍历线索化二叉树 5.1.先序遍历 先序 ...

  3. 中序线索化二叉树c语言实现

    ```c #include<stdio.h>//首先定义一个遍历前驱的节点ThreadNode *pre = NULL;//指向前驱节点typedef struct ThreadNode ...

  4. 数据结构2:中序线索化二叉树为什么要通过pre设置后继结点

    在听尚硅谷韩顺平老师课程的时候这个地方没有理解,先把java中序线索化二叉树代码附上: private HeroNode pre = null;//在递归线索化,pre总是保留前一个结点 /**** ...

  5. Java实现前中后序线索化二叉树以及遍历

    文章目录 一.线索化二叉树的原理 二.构建线索化二叉树 三.代码实现线索二叉树 一.线索化二叉树的原理 在前面介绍二叉树的文章中提到,二叉树可以使用两种存储结构:顺序存储和链式存储,在使用链式存储时, ...

  6. 后序线索化二叉树及遍历(图解)

    上一篇博客对于 二叉树线索化以及线索化的先序.中序.后序遍历做了比较详细的描述 写在前面 其实,我还是很想把本篇博客和二叉树的线索化写在一块的,但是考虑到可能这博客的内容就看足以超过了上一篇的篇幅,考 ...

  7. 数据结构与算法(java):树-二叉树(二叉查找树(BST)、线索化二叉树、哈夫曼树、平衡二叉树【AVL】、二叉树的前中后序遍历)

    二叉树 1.定义 二叉树 就是度不超过2的树(每个结点最多只有两个子结点).如图 2.特殊二叉树 满二叉树 当二叉树的每一个层的结点树都达到最大值,则这个二叉树就是满二叉树. 完全二叉树 叶结点只能出 ...

  8. node 获取表单数据 为空_程序员:数据结构和算法,中序线索化二叉树

    1.中序线索化二叉树   创建如上的二叉树,线索化二叉树时,根据指定的遍历方式得到的节点的访问顺序,一个节点前面的节点,叫做前驱节点,一个节点后面的节点,叫做后继节点.   线索化二叉树的规则:   ...

  9. 线索化二叉树,中序建立线索,带线索中序遍历,删除,c/c++描述

      二叉树的叶节点的两个指针都没有利用,一些分支节点也可能有一个指针指向NULL,这些指针造成了程序在内存空间上的浪费,但这些叶节点也必不可省.所以我们可以把这些指向NULL的指针,重新赋值,左指针则 ...

最新文章

  1. Html_div圆角
  2. 现代软件工程 第十二章 【用户体验】练习与讨论
  3. 计算机网络总结:第五章 链路层
  4. 笔记本电脑没有鼠标怎么右键_联想笔记本电脑没有声音怎么修复
  5. ServerSuperIO Designer IDE 发布,打造物联网通讯大脑,随心而联。附:C#驱动源代码。
  6. 朝着理想坚实迈进_坚实原则:接口隔离原则
  7. 基于NPOI的报表引擎——ExcelReport
  8. AI大有可为:NAIE平台助力垃圾分类
  9. 临界区设计太大或太小有何缺点_小户型太小怎么办?17个实用空间设计拯救你家,小家越住越大...
  10. win10红警2黑屏_win10每次重启黑屏假死
  11. 公司内部分享【富有成效的每日站会】总结
  12. XP安装JDK1.8
  13. win 7 与 virtualbox ubuntu 共享文件夹
  14. JRE和JDK的区别(笔记)
  15. AE/PR模板:10组电影质感海报宣传文字标题设计动画Cinematic Titles
  16. 阿里云验证码与通知短信
  17. 去掉首尾字符java_Java去除字符串首尾特定字符
  18. 香港珠宝零售商将使用区块链平台追踪钻石
  19. HTTP 和 Request
  20. Error: Can't place multiple pins assigned to pin location……解决办法

热门文章

  1. 查询计算机系的读者信息,简单查询
  2. Git的下载和基本使用
  3. 画心的方法_书画常识:怎样保存书画的画心
  4. 7年华为老员工被辞退,公司赔偿N+4,网友:多拿11个月工资,爽翻
  5. Android布局之ConstraintLayout布局
  6. 用RTKLIB中的rtkpost进行ppp和spp定位(附用CUI rnx2rtkp 编译)
  7. python 将姓名 除姓外用*代替和手机号中间4位用****代替
  8. java set遍历删除元素_java中循环遍历删除List和Set集合中元素的方法
  9. java中遍历集合_java中遍历ArrayList集合的四种方式
  10. mac 蓝牙键盘 鼠标难用_如何在Mac上设置蓝牙键盘或鼠标