线索二叉树分别在节点中子树为空时设为其前驱或者后继节点,其遍历中序线索二叉树效率会比较高一点。该程序可实现线索二叉树包括中序遍历等基本操作,代码如下:
xiansuotree.c主要为线索二叉树的基本操作函数
//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: 线索二叉树的基本操作
#include "xiansuotree.h"
ThreadBinTree *Previous=NULL; //前驱结点指针
/******************************************************
函数名:
参数:bt为父结点,node为子结点,n=1表示添加左子树,n=2表示添加右子树
功能:添加数据到二叉树
*******************************************************/
int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n)
{
if(bt==NULL)
{
printf("父结点不存在,请先设置父结点!\n");
return 0;
}
switch(n)
{
case 1: //添加到左结点
if(bt->left) //左子树不为空
{
printf("左子树结点不为空!\n");
return 0;
}else
bt->left=node;
break;
case 2://添加到右结点
if( bt->right) //右子树不为空
{
printf("右子树结点不为空!\n");
return 0;
}
else
bt->right=node;
break;
default:
printf("参数错误!\n");
return 0;
}
return 1;
}
/******************************************************
函数名:BinTreeFind(ThreadBinTree *bt,DATA data)
参数:树节点,数据
功能:在二叉树中查找值为data的结点
*******************************************************/
ThreadBinTree *BinTreeFind(ThreadBinTree *bt,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(ThreadBinTree *bt)
参数:树节点
功能:清空二叉树,使之变为一棵空树
*******************************************************/
void BinTreeClear(ThreadBinTree *bt)
{
if(bt)//该节点不为空
{
BinTreeClear(bt->left); //清空左子树
BinTreeClear(bt->right);//清空右子树
free(bt);//释放当前结点所占内存
bt=NULL;
}
return;
}
/******************************************************
函数名:BinTreeThreading_LDR(ThreadBinTree *bt)
参数:树结点
功能:二叉树按中序线索化
*******************************************************/
void BinTreeThreading_LDR(ThreadBinTree *bt)
{
if(bt) //结点非空时,当前访问结点
{
BinTreeThreading_LDR(bt->left); //递归调用,将左子树线索化
//bt->left为真就取SubTree(子树),否则为前驱
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(ThreadBinTree *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(ThreadBinTree *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->right;
return prenode; //返回右下方的结点
}
}
/******************************************************
函数名:ThreadBinTree_LDR(ThreadBinTree *bt,void (*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);
}
}
/******************************************************
函数名:oper(ThreadBinTree *p)
参数:树节点
功能:操作二叉树结点数据
*******************************************************/
void oper(ThreadBinTree *p)
{
printf("%c ",p->data); //输出数据
return;
}
/******************************************************
函数名:InitRoot()
参数:无
功能:初始化二叉树的根
*******************************************************/
ThreadBinTree *InitRoot()
{
ThreadBinTree *node;
if(node=(ThreadBinTree *)malloc( sizeof(ThreadBinTree))) //分配内存
{
printf("\n输入根结点数据:");
scanf("%s",&node->data);
node->left=NULL;
node->right=NULL;
return node;
}
return NULL;
}
/******************************************************
函数名:AddNode(ThreadBinTree *bt)
参数:树节点
功能:增加特定父节点的子结点
*******************************************************/
void AddNode(ThreadBinTree *bt)
{
ThreadBinTree *node,*parent;
DATA data;
char select;
if(node=(ThreadBinTree *)malloc(sizeof(ThreadBinTree))) //分配内存
{
printf("\n输入二叉树结点数据:");
scanf("%s",&node->data);
node->left=NULL; //设置左右子树为空
node->right=NULL;
printf("输入父结点数据:");
scanf("%s",&data);
parent=BinTreeFind(bt,data);//查找指定数据的结点
if(!parent)//若未找到指定数据的结点
{
printf("未找到父结点!\n");
free(node); //释放创建的结点内存
return;
}
printf("1.添加到左子树\n2.添加到右子树\n");
do{
select=getchar();
select-='0';
if(select==1 || select==2)
BinTreeAddNode(parent,node,select); //添加结点到二叉树
}while(select!=1 && select!=2);
}
return ;
}
lcwxiansuo.c为主函数,主要实现其验证
//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: 线索二叉树操作验证函数
#include "xiansuotree.h"
int main()
{
ThreadBinTree *root=NULL; //root为指向二叉树根结点的指针
char select;
void (*oper1)(); //指向函数的指针
oper1=oper; //指向具体操作的函数
do{
printf("\n1.设置二叉树根元素 2.添加二叉树结点\n");
printf("3.生成中序线索二叉树 4.遍历线索二叉树\n");
printf("00.退出\n");
select=getchar();
switch(select)
{
case '1': //设置根元素
root=InitRoot();
break;
case '2': //添加结点
AddNode(root);
break;
case '3'://生成中序线索二叉树
BinTreeThreading_LDR(root);
printf("\n生成中序线索二叉树完毕!\n");
break;
case '4'://遍历中序线索二叉树
printf("\n中序线索二叉树遍历的结果:");
ThreadBinTree_LDR(root,oper1);
printf("\n");
break;
case '0':
break;
}
select=getchar();//这里加一个去掉回车符
}while(select!='0');
BinTreeClear(root);//清空二叉树
root=NULL;
return 0;
}
该头文件包括基本的数据结构和函数的声明
//start from the very beginning,and to create greatness
//@author: Chuangwei Lin
//@E-mail:979951191@qq.com
//@brief: 线索二叉树基本操作的头文件
#include <stdio.h>
#include <stdlib.h>
typedef char DATA; //定义元素类型
//枚举
typedef enum
{
SubTree, //枚举值SubTree(子树)为0
Thread //Thread(线索)为1
}NodeFlag;
typedef struct ThreadTree //定义线索二叉树结点类型
{
DATA data; //元素数据
NodeFlag lflag; //左标志,其取值只有两种
NodeFlag rflag; //右标志
struct ThreadTree *left; //左子树结点指针
struct ThreadTree *right; //右子树结点指针
}ThreadBinTree;
int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n);
ThreadBinTree *BinTreeFind(ThreadBinTree *bt,DATA data);
void BinTreeClear(ThreadBinTree *bt);
void BinTreeThreading_LDR(ThreadBinTree *bt);
ThreadBinTree *BinTreeNext_LDR(ThreadBinTree *bt);
ThreadBinTree *BinTreePrevious_LDR(ThreadBinTree *bt);
void ThreadBinTree_LDR(ThreadBinTree *bt,void (*oper)(ThreadBinTree *p));
void oper(ThreadBinTree *p);
ThreadBinTree *InitRoot();
void AddNode(ThreadBinTree *bt);
运行结果如下:
建立了一个线索二叉树,然后生成中序线索二叉树,最后遍历线索二叉树