线索二叉树操作

(1) 线索二叉树的表示:将每个节点中为空的做指针与右指针分别用于指针节点的前驱和后续,即可得到线索二叉树。

(2) 分类:先序线索二叉树,中序线索二叉树,后续线索二叉树

(3) 增加线索标志域后,二叉链表的结构如下:

typedef enum
{
SubTree,
Thread
}NodeFlag; //枚举值SubTree(子树)和Thread(线索)分别为0,1
typedef struct ThreadTree //定义线索二叉树结点类型
{
DATA data; //元素数据
NodeFlag lflag; //左标志
NodeFlag rflag; //右标志
struct ThreadTree *left; //左子树结点指针
struct ThreadTree *right; //右子树结点指针
}ThreadBinTree;

(4) 操作线索二叉树:

    a)   查找后续节点:

i.  若父节点P的右子树为空,则p->right为右线索,直接指向p的中序后续。

ii.  若父节点p的右子树不为空,则p的中序后续必是其右子树中第一个中序遍历到的节点。

    b)   查找前驱节点:

i. 若父节点p的左子树为空,则p->left为左线索,直接指向p的中序前驱节点

ii.   若父节点p的左子树不为空,则从p的左子树出发,沿该子树的右指针链表往下查找,直到一个没有右子树的节点为止,则该及诶按就是p 的中序前驱节点。

        c)  遍历线索二叉树:由于二叉树被线索化,遍历时可根据后续指针快速完成,而不使用递归调用即可完成。

(5) 对二叉树进行中序线索化。C语言实现代码如下:

/*
********************************************************************************
* 数据结构
*
*
*
* 作者: zhi-z
*
* QQ号: 2282643301
*
********************************************************************************
*文件名 : ThreadBinTree.c
*作用 : 线索二叉树 操作
*原理 :
********************************************************************************
*版本 作者 日期 说明
*V0.1 2016-10-3 初始版本
********************************************************************************
*/ #include <stdio.h>
#include <stdlib.h>
#define QUEUE_MAXSIZE 50 /********************************************************************************
*数据结构名 : ThreadTree
*参数 :
*作用 : 定义线索二叉树的数据结构
*内容 :
*
********************************************************************************/
typedef char DATA; //定义元素类型
typedef enum
{
SubTree,
Thread
}NodeFlag; //枚举值SubTree(子树)和Thread(线索)分别为0,1
typedef struct ThreadTree //定义线索二叉树结点类型
{
DATA data; //元素数据
NodeFlag lflag; //左标志
NodeFlag rflag; //右标志
struct ThreadTree *left; //左子树结点指针
struct ThreadTree *right; //右子树结点指针
}ThreadBinTree; ThreadBinTree *Previous=NULL; //前驱结点指针 /********************************************************************************
*函数名 : BinTreeInit
*参数 :node:线索二叉树的一个节点
*作用 : 初始化线索二叉树
*内容 :
*
********************************************************************************/
ThreadBinTree *BinTreeInit(ThreadBinTree *node) //初始化二叉树根结点
{
if(node!=NULL) //若二叉树根结点不为空
return node;
else
return NULL;
} /********************************************************************************
*函数名 : BinTreeAddNode
*参数 :bt为父结点,node为子结点,n=1表示添加左子树,n=2表示添加右子树
*作用 : 添加数据到二叉树
*内容 :
*
********************************************************************************/
int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n) //添加数据到二叉树
//bt为父结点,node为子结点,n=1表示添加左子树,n=2表示添加右子树
{
if(bt==NULL)
{
printf("父结点不存在,请先设置父结点!\n");
return ;
}
switch(n)
{
case : //添加到左结点
if(bt->left) //左子树不为空
{
printf("左子树结点不为空!\n");
return ;
}else
bt->left=node;
break;
case ://添加到右结点
if( bt->right) //右子树不为空
{
printf("右子树结点不为空!\n");
return ;
}else
bt->right=node;
break;
default:
printf("参数错误!\n");
return ;
}
return ;
} /********************************************************************************
*函数名 : BinTreeLeft
*参数 :bt:为父结点
*作用 : 返回左子结点
*内容 :
*
********************************************************************************/
ThreadBinTree *BinTreeLeft(ThreadBinTree *bt) //返回左子结点
{
if(bt)
return bt->left;
else
return NULL;
} /********************************************************************************
*函数名 : BinTreeRight
*参数 :bt:为父结点
*作用 : 返回右子结点
*内容 :
*
********************************************************************************/
ThreadBinTree *BinTreeRight(ThreadBinTree *bt) //返回右子结点
{
if(bt)
return bt->right;
else
return NULL;
} /********************************************************************************
*函数名 : BinTreeIsEmpty
*参数 :bt:为父结点
*作用 : 检查二叉树是否为空,为空则返回1,否则返回0
*内容 :判断线索二叉树是否为空(操作与二叉树相同)
*
********************************************************************************/
int BinTreeIsEmpty(ThreadBinTree *bt) //检查二叉树是否为空,为空则返回1,否则返回0
{
if(bt)
return ;
else
return ;
} /********************************************************************************
*函数名 : BinTreeDepth
*参数 :bt:为父结点
*作用 : 求二叉树深度
*内容 :(操作与二叉树相同)
*
********************************************************************************/
int BinTreeDepth(ThreadBinTree *bt) //求二叉树深度
{
int dep1,dep2;
if(bt==NULL)
return ; //对于空树,深度为0
else
{
dep1 = BinTreeDepth(bt->left); //左子树深度 (递归调用)
dep2 = BinTreeDepth(bt->right); //右子树深度 (递归调用)
if(dep1>dep2)
return dep1 + ;
else
return dep2 + ;
}
} /********************************************************************************
*函数名 : BinTreeFind
*参数 :bt:为父结点,data:要查找的数据
*作用 : 在二叉树中查找值为data的结点
*内容 :(操作与二叉树相同)
*
********************************************************************************/
ThreadBinTree *BinTreeFind(ThreadBinTree *bt,DATA data) //在二叉树中查找值为data的结点
{
ThreadBinTree *p;
if(bt==NULL)
return NULL;
else
{
if(bt->data==data)
return bt;
else{ // 分别向左右子树递归查找
if(p=BinTreeFind(bt->left,data))
return p;
else if(p=BinTreeFind(bt->right, data))
return p;
else
return NULL;
}
}
} /********************************************************************************
*函数名 : BinTreeClear
*参数 :bt:为父结点
*作用 : 清空二叉树,使之变为一棵空树
*内容 :(操作与二叉树相同)
*
********************************************************************************/
void BinTreeClear(ThreadBinTree *bt) // 清空二叉树,使之变为一棵空树
{
if(bt)
{
BinTreeClear(bt->left); //清空左子树
BinTreeClear(bt->right);//清空右子树
free(bt);//释放当前结点所占内存
bt=NULL;
}
return;
} /********************************************************************************
*函数名 : BinTree_DLR
*参数 :bt:为父结点,(*oper)(ThreadBinTree *p):二叉树的操作
*作用 : 先序遍历
*内容 :
*
********************************************************************************/
void BinTree_DLR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p)) //先序遍历
{
if(bt)//树不为空,则执行如下操作
{
oper(bt); //处理结点的数据
BinTree_DLR(bt->left,oper);
BinTree_DLR(bt->right,oper);
}
return;
} /********************************************************************************
*函数名 : BinTree_LDR
*参数 :bt:为父结点,(*oper)(ThreadBinTree *p):二叉树的操作
*作用 : 中序遍历
*内容 :
*
********************************************************************************/
void BinTree_LDR(ThreadBinTree *bt,void(*oper)(ThreadBinTree *p)) //中序遍历
{
if(bt)//树不为空,则执行如下操作
{
BinTree_LDR(bt->left,oper); //中序遍历左子树
oper(bt);//处理结点数据
BinTree_LDR(bt->right,oper); //中序遍历右子树/
}
return;
} /********************************************************************************
*函数名 : BinTree_LRD
*参数 :bt:为父结点,(*oper)(ThreadBinTree *p):二叉树的操作
*作用 : 后序遍历
*内容 :
*
********************************************************************************/
void BinTree_LRD(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p)) //后序遍历
{
if(bt)
{
BinTree_LRD(bt->left,oper); //后序遍历左子树
BinTree_LRD(bt->right,oper); //后序遍历右子树/
oper(bt); //处理结点数据
}
return;
} /********************************************************************************
*函数名 : BinTree_Level
*参数 :bt:为父结点,(*oper)(ThreadBinTree *p):二叉树的操作
*作用 : 按层遍历
*内容 :
*
********************************************************************************/
void BinTree_Level(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p)) //按层遍历
{
ThreadBinTree *p;
ThreadBinTree *q[QUEUE_MAXSIZE]; //定义一个顺序栈
int head=,tail=;//队首、队尾序号
if(bt)//若队首指针不为空
{
tail=(tail+)%QUEUE_MAXSIZE;//计算循环队列队尾序号
q[tail] = bt;//将二叉树根指针进队
}
while(head!=tail) //队列不为空,进行循环
{
head=(head+)%QUEUE_MAXSIZE; //计算循环队列的队首序号
p=q[head]; //获取队首元素
oper(p);//处理队首元素
if(p->left!=NULL) //若结点存在左子树,则左子树指针进队
{
tail=(tail+)%QUEUE_MAXSIZE;//计算循环队列的队尾序号
q[tail]=p->left;//将左子树指针进队
} if(p->right!=NULL)//若结点存在右孩子,则右孩子结点指针进队
{
tail=(tail+)%QUEUE_MAXSIZE;//计算循环队列的队尾序号
q[tail]=p->right;//将右子树指针进队
}
}
return;
} /********************************************************************************
*函数名 : BinTreeThreading_LDR
*参数 :bt:为父结点
*作用 : 二叉树按中序线索化
*内容 :
*
********************************************************************************/
void BinTreeThreading_LDR(ThreadBinTree *bt) //二叉树按中序线索化
{
if(bt) //结点非空时,当前访问结点
{
BinTreeThreading_LDR(bt->left); //递归调用,将左子树线索化
bt->lflag=(bt->left)?SubTree:Thread; //设置左指针域的标志
bt->rflag=(bt->right)?SubTree:Thread;//设置右指针域的标志
if(Previous) //若当前结点的前驱Previous存在
{
if(Previous->rflag==Thread) //若当前结点的前驱右标志为线索
Previous->right=bt;//设Previous的右线索指向后继
if(bt->lflag==Thread) //若当前结点的左标志为线索
bt->left=Previous;//设当前结点的左线索指向中序前驱
}
Previous=bt;//让Previous保存刚访问的结点
BinTreeThreading_LDR(bt->right);//递归调用,将右子树线索化
}
} /********************************************************************************
*函数名 : BinTreeNext_LDR
*参数 :bt:为父结点
*作用 : 求指定结点的后继
*内容 :
*
********************************************************************************/
ThreadBinTree *BinTreeNext_LDR(ThreadBinTree *bt) //求指定结点的后继
{
ThreadBinTree *nextnode;
if(!bt) return NULL; //若当前结点为空,则返回空
if(bt->rflag==Thread) //若当前结点的右子树为空
return bt->right; //返回右线索所指的中序后继
else{
nextnode=bt->right; //从当前结点的右子树开始查找
while(nextnode->lflag==SubTree) //循环处理所有左子树不为空的结点
nextnode=nextnode->left;
return nextnode; //返回左下方的结点
}
} /********************************************************************************
*函数名 : BinTreePrevious_LDR
*参数 :bt:为父结点
*作用 : 求指定结点的前驱
*内容 :
*
********************************************************************************/
ThreadBinTree *BinTreePrevious_LDR(ThreadBinTree *bt) //求指定结点的前驱
{
ThreadBinTree *prenode;
if(!bt) return NULL; //若当前结点为空,则返回空
if(bt->lflag==Thread) //若当前结点的左子树为空
return bt->left; //返回左线索所指的中序后继
else{
prenode=bt->left; //从当前结点的左子树开始查找
while(prenode->rflag==SubTree) //循环处理所有右子树不为空的结点
prenode=prenode->left;
return prenode; //返回左下方的结点
}
} /********************************************************************************
*函数名 : ThreadBinTree_LDR
*参数 :bt:为父结点 ,(*oper)(ThreadBinTree *p):二叉树的操作
*作用 :遍历中序线索二叉树
*内容 :
*
********************************************************************************/
void ThreadBinTree_LDR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p)) //遍历中序线索二叉树
{
if(bt) //二叉树不为空
{
while(bt->lflag==SubTree)//有左子树
bt=bt->left; //从根往下找最左下结点,即中序序列的开始结点
do{
oper(bt); //处理结点
bt=BinTreeNext_LDR(bt);//找中序后继结点
}while(bt);
}
}

数据结构之线索二叉树——C语言实现的更多相关文章

  1. javascript实现数据结构:线索二叉树

    遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作.如何找到遍历过程中动态得到的每个结点的直接前驱和直接后继(第一个和最后一个除外)?如何保存这些信息? 设一棵二叉树 ...

  2. 【PHP数据结构】完全二叉树、线索二叉树及树的顺序存储结构

    在上篇文章中,我们学习了二叉树的基本链式结构以及建树和遍历相关的操作.今天我们学习的则是一些二叉树相关的概念以及二叉树的一种变形形式. 完全二叉树 什么叫完全二叉树呢?在说到完全二叉树之前,我们先说另 ...

  3. 数据结构之---C语言实现线索二叉树

    //线索二叉树,这里在二叉树的基础上增加了线索化 //杨鑫 #include <stdio.h> #include <stdlib.h> typedef char ElemTy ...

  4. 【Java】 大话数据结构(9) 树(二叉树、线索二叉树)

    本文根据<大话数据结构>一书,对Java版的二叉树.线索二叉树进行了一定程度的实现. 另: 二叉排序树(二叉搜索树) 平衡二叉树(AVL树) 二叉树的性质 性质1:二叉树第i层上的结点数目 ...

  5. 数据结构《9》----Threaded Binary Tree 线索二叉树

    对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为  n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...

  6. 线索二叉树的理解和实现(Java)

    线索二叉树的基本概念 我们按某种方式对二叉树进行遍历,将二叉树中所有节点排序为一个线性序列,在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点:除最后一个结点外每一个结点有且仅有一个直接后继结 ...

  7. [线索二叉树] [LeetCode] 不需要栈或者别的辅助空间,完成二叉树的中序遍历。题:Recover Binary Search Tree,Binary Tree Inorder Traversal

    既上篇关于二叉搜索树的文章后,这篇文章介绍一种针对二叉树的新的中序遍历方式,它的特点是不需要递归或者使用栈,而是纯粹使用循环的方式,完成中序遍历. 线索二叉树介绍 首先我们引入“线索二叉树”的概念: ...

  8. 《数据结构与算法分析:C语言描述》读书笔记

    我们数据结构的课用了这本英文教材,作者是Mark Allen Weiss.总体来说比<算法导论>简单很多,但内容上交集非常大.其实是因为去掉了大多数证明和数学,对于没有耐心看符号和公式的人 ...

  9. 【数据结构与算法】多种语言(VB、C、C#、JavaScript)系列数据结构算法经典案例教程合集目录

    目录 1. 专栏简介 2. 专栏地址 3. 专栏目录 1. 专栏简介 2. 专栏地址 「 刘一哥与GIS的故事 」之<数据结构与算法> 3. 专栏目录 [经典回放]多种语言系列数据结构算法 ...

随机推荐

  1. SUST OJ 1641: 电子狗的心事

    1641: 电子狗的心事 时间限制: 1 Sec  内存限制: 128 MB提交: 192  解决: 14[提交][状态][讨论版] 题目描述 计算机程序世界中有一位孤独的电子狗,这个电子狗每次只能执 ...

  2. CTF-练习平台-Misc之 细心的大象

    十五.细心的大象 打开图片属性 发现备注里有短信息,看着也不像flag,仔细观察里面只有只有大小写字母和数字应该是base64编码,解密后得到:MSDS456ASD123zz 好像也不是flag,题目 ...

  3. hdu5228

    bc41第一题 德州扑克的背景,给出五张牌,问最少要换多少张牌能凑齐同花顺 其实很水,数据量很小,随便暴力,越粗暴越好,然后我wa了一发因为没有看全题目,10\11\12\13\1也是一组同花顺``` ...

  4. benthos 几个方便的帮助命令

    benthos 的命令行帮助做的是比较方便的,基本上就是一个自包含的帮助文档 全部命令 benthos --help 查询系统支持的caches benthos -list-caches 说明 使用帮 ...

  5. ORACLE与SQL SERVER语法区别

    一.数据类型 ORACLE与SQL SERVER在数据类型的对比如下: SQL SERVER ORACLE 数字类型 DECIMAL[(P[, S])] NUMBER[(P[, S])] NUMERI ...

  6. NSDate 时间加减

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/pearlhuzhu/article/details/26227393 NSDate有个类别,例如以下 ...

  7. 变量延迟(setlocal)之浅见

    变量延迟,浅见认为就是变量预处理,在事先声明变量,告诉cmd环境哪个先哪个后.默认情况下是停用,可以用两种方法启用/停用: 一.cmd /v:on 和cmd /v:off ,范围在cmd这个环境直至e ...

  8. 单变量微积分笔记21——三角替换2(tan和sec)

    tan和sec常用公式 我一直认为三角函数中只有sin和cos是友好的,其它都是变态.现在不得不接触一些变态: 这些变态的相关等式: 等式的证明 这个稍有点麻烦,先要做一些前置工作. 三角替换 示例1 ...

  9. Microsoft Dynamics CRM 2013 安装 报表服务出现“ SQL Server Reporting Services 帐户是本地用户且不受支持 ”错误的解决方法

    安装好CRM 2013 之后,还需要安装报表服务,发现出现:SQL Server Reporting Services 帐户是本地用户且不受支持,具体如下图: 经过分析原来发现是需要用域用户,打开对应 ...

  10. yield对性能提升的一次小小测试

    生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低.生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中 ...