构造中序线索二叉树和先序线索二叉树,中序线索二叉树找寻前驱结点和后继结点,包含完整代码

一.线索二叉树的结点结构:

lchildltagdatartagrchild

ltag = 0,   lchild域指示结点的左孩子

ltag = 1,   lchild域指示结点的前驱

rtag = 0,   rchild域指示结点的右孩子

rtag = 1,   rchild域指示结点的后继

这里用char型作为树的数据域类型

//定义线索二叉树的结构体
typedef struct ThreadNode
{
  char data;
  struct ThreadNode *lchild,*rchild;
  int ltag,rtag;
}ThreadNode,*ThreadTree;

二.如何找寻结点的前驱和后继

先将二叉树进行遍历然后根据遍历结构来找前驱和后继

以该例子的中序来表示,该二叉树的中序遍历为:BADCE

 B的前驱结点为NULL,后继结点为A

A的前驱结点为B,后继结点为D

D的前驱结点为A,后继结点为C

C的前驱结点为D,后继结点为E

E的前驱节点为C,后继结点为NULL

由上图可以看出有的结点的指针域是空的,这样可以利用这些空的指针域,若左孩子指针域为空可以指向该结点的前驱结点;若右孩子为空,可以指向该结点的后继结点

红色线表示前驱指向前驱结点,黄色线表示指向后继结点

三.二叉树线索化过程

1.先通过字符串为二叉树赋值

字符串结构体

//定义字符串的结构体
typedef struct SString
{
  char ch[Maxsize];
  int length;
}SString;

 串赋值操作

//串的赋值操作
void StrAssign(SString &S, char *chars)
{
  if(strlen(chars) > Maxsize)
	  exit(-1);
  S.length = strlen(chars);
  S.ch[0] = S.length;
  for(int i = 1; i <= S.length; ++i )
  {
	  S.ch[i] = *(chars+i-1);
  }
}

构造二叉树

//先创造一棵树,将chars元素赋值给树
void CreatTree(ThreadTree &T)
{
	char ch = S.ch[i++];
	if(ch == '#')
		T = NULL;
	else
	{
	  T = (ThreadTree)malloc(sizeof(ThreadNode));
	  if(T == NULL)
	  {
	    printf("动态内存分配失败,结束程序!\n");
		exit(-1);
	  }
	  T->data = ch;
	  CreatTree(T->lchild);
	  if(T->lchild != NULL)
		  T->ltag = 0;
	  CreatTree(T->rchild);
	  if(T->rchild != NULL)
		  T->rtag = 0;
	}
}

2.中序遍历线索二叉树

//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree &T)
{
  if(T != NULL)
  {
	  InThread(T->lchild);//中序遍历左子树
	  Visit(T);//访问结点
	  InThread(T->rchild);//中序遍历右子树

  }
}

访问结点函数

//访问节点
void Visit(ThreadNode *p)
{
	if(p->lchild == NULL)//如果左子树为空,建立前驱线索
	{
		p->lchild = Pre;
		p->ltag = 1;
	}
	if(Pre != NULL && p->rchild == NULL)//建立后继线索
	{
		p->rchild = Pre;
		p->rtag = 1;
	}
	Pre = p;
}

中序线索化二叉树

//中序线索化二叉树
void CreatInThread(ThreadTree &T)
{
  Pre = NULL;//初始时Pre为NULL
  if(T != NULL)//非空二叉树才能够线索化
  {
    InThread(T);//中序线索化
	if(Pre->rchild == NULL)
		Pre->rtag = 1;//处理遍历的最后一个结点
  }
}

3.找前驱结点

首先是找到以P为根结点的的子树中,最后一个被中序遍历的结点

//中序线索二叉树找中序前驱,线索二叉树中序遍历中,以P为根结点,则P的前驱肯定是在P的左子树中最右下结点
//找到以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;
}

4.找后继结点

找左子树最左下结点

//中序线索二叉树找中序后继,在中序线索二叉树中,若是找根结点的后继节点,那么肯定是右子树中第一个遍历的结点
//右子树的最左下结点
ThreadNode *firstnode(ThreadNode *P)
{
	while(P->ltag == 0)
		P = P->lchild;
	return P;
}

右子树最左下结点 

//在中序遍历的线索二叉树中,以P为根节点,找P结点的中序遍历后继结点
ThreadNode *nextnode(ThreadNode *P)
{//右子树最左下结点
	if(P->rtag == 0)
		return firstnode(P->rchild);
	else
		return P->rchild;
}

结果

 5.二叉树先序遍历线索化

//先序遍历线索化,一边遍历一边线索化
void PreThread(ThreadTree T)
{
  if(T != NULL)
  {
    Visit(T);//先访问根结点
	if(T->ltag == 0)//防止因为线索而导致一直循环
		PreThread(T->lchild);//访问左子树
	PreThread(T->rchild);//访问右子树
  }
}

//创造先序线索化二叉树
void CreatPreThread(ThreadTree T)
{
  Pre = NULL;
  if(T != NULL)
  {
    PreThread(T);
	if(Pre->rchild == NULL)
		Pre->rtag = 1;//处理最后一个结点
  }
}

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<string.h>

#define Maxsize 11

//定义线索二叉树的结构体
typedef struct ThreadNode
{
  char data;
  struct ThreadNode *lchild,*rchild;
  int ltag,rtag;
}ThreadNode,*ThreadTree;
//定义一个全局变量
ThreadNode *Pre = NULL;

//定义字符串的结构体
typedef struct SString
{
  char ch[Maxsize];
  int length;
}SString;

//定义一个全局变量的字符串
SString S;
int i = 1;

//串的函数说明
void StrAssign(SString &S, char *chars);

//树的函数说明
void CreatTree(ThreadTree &T);
void InThread(ThreadTree &T);
void Visit(ThreadNode *p);
void CreatInThread(ThreadTree &T);
ThreadNode *LastNode(ThreadNode *P);
ThreadNode *Prenode(ThreadNode *P);
ThreadNode *firstnode(ThreadNode *P);
ThreadNode *nextnode(ThreadNode *P);

int main(void)
{
  ThreadTree T;
  StrAssign(S,"AB##CD##E##");
  CreatTree(T);
  ThreadNode *V1 = Prenode(T);
  ThreadNode *V2 = nextnode(T);
  printf("根结点的前驱结点的值为:%c\n",V1->data);
  printf("根结点的后继结点的值为:%c\n",V2->data);

  return 0;
}

//串的赋值操作
void StrAssign(SString &S, char *chars)
{
  if(strlen(chars) > Maxsize)
	  exit(-1);
  S.length = strlen(chars);
  S.ch[0] = S.length;
  for(int i = 1; i <= S.length; ++i )
  {
	  S.ch[i] = *(chars+i-1);
  }
}

//先创造一棵树,将chars元素赋值给树
void CreatTree(ThreadTree &T)
{
	char ch = S.ch[i++];
	if(ch == '#')
		T = NULL;
	else
	{
	  T = (ThreadTree)malloc(sizeof(ThreadNode));
	  if(T == NULL)
	  {
	    printf("动态内存分配失败,结束程序!\n");
		exit(-1);
	  }
	  T->data = ch;
	  CreatTree(T->lchild);
	  if(T->lchild != NULL)
		  T->ltag = 0;
	  CreatTree(T->rchild);
	  if(T->rchild != NULL)
		  T->rtag = 0;
	}
}


//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree &T)
{
  if(T != NULL)
  {
	  InThread(T->lchild);//中序遍历左子树
	  Visit(T);//访问结点
	  InThread(T->rchild);//中序遍历右子树

  }
}

//访问节点
void Visit(ThreadNode *p)
{
	if(p->lchild == NULL)//如果左子树为空,建立前驱线索
	{
		p->lchild = Pre;
		p->ltag = 1;
	}
	if(Pre != NULL && p->rchild == NULL)//建立后继线索
	{
		p->rchild = Pre;
		p->rtag = 1;
	}
	Pre = p;
}

//中序线索化二叉树
void CreatInThread(ThreadTree &T)
{
  Pre = NULL;//初始时Pre为NULL
  if(T != NULL)//非空二叉树才能够线索化
  {
    InThread(T);//中序线索化
	if(Pre->rchild == NULL)
		Pre->rtag = 1;//处理遍历的最后一个结点
  }
}

//中序线索二叉树找中序前驱,线索二叉树中序遍历中,以P为根结点,则P的前驱肯定是在P的左子树中最右下结点
//找到以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;
}



//中序线索二叉树找中序后继,在中序线索二叉树中,若是找根结点的后继节点,那么肯定是右子树中第一个遍历的结点
//右子树的最左下结点
ThreadNode *firstnode(ThreadNode *P)
{
	while(P->ltag == 0)
		P = P->lchild;
	return P;
}

//在中序遍历的线索二叉树中,以P为根节点,找P结点的中序遍历后继结点
ThreadNode *nextnode(ThreadNode *P)
{//右子树最左下结点
	if(P->rtag == 0)
		return firstnode(P->rchild);
	else
		return P->rchild;
}


//先序遍历线索化,一边遍历一边线索化
void PreThread(ThreadTree T)
{
  if(T != NULL)
  {
    Visit(T);//先访问根结点
	if(T->ltag == 0)//防止因为线索而导致一直循环
		PreThread(T->lchild);//访问左子树
	PreThread(T->rchild);//访问右子树
  }
}

//创造先序线索化二叉树
void CreatPreThread(ThreadTree T)
{
  Pre = NULL;
  if(T != NULL)
  {
    PreThread(T);
	if(Pre->rchild == NULL)
		Pre->rtag = 1;//处理最后一个结点
  }
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值