【数据结构】线索二叉树

线索二叉树:指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded Binary Tree)。

线索化:对二叉树以某种次序遍历使其变为线索二叉树称作是线索化。线索化的过程就是在遍历的过程中修改空指针的过程。

代码:

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100 /* 存储空间初始分配量 */

typedef int Status;	/* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef char TElemType;
typedef enum {Link,Thread} PointerTag;	/* Link==0表示指向左右孩子指针, */
										/* Thread==1表示指向前驱或后继的线索 */
typedef  struct BiThrNode	/* 二叉线索存储结点结构 */
{
	TElemType data;	/* 结点数据 */
	struct BiThrNode *lchild, *rchild;	/* 左右孩子指针 */
	PointerTag LTag;
	PointerTag RTag;		/* 左右标志 */
} BiThrNode, *BiThrTree;

TElemType Nil='#'; /* 字符型以空格符为空 */

Status visit(TElemType e)
{
	printf("%c ",e);
	return OK;
}

/* 按前序输入二叉线索树中结点的值,构造二叉线索树T */
/* 0(整型)/空格(字符型)表示空结点 */
Status CreateBiThrTree(BiThrTree *T)
{
	TElemType h;
	scanf("%c",&h);

	if(h==Nil)
		*T=NULL;
	else
	{
		*T=(BiThrTree)malloc(sizeof(BiThrNode));
		if(!*T)
			exit(OVERFLOW);
		(*T)->data=h; /* 生成根结点(前序) */
		CreateBiThrTree(&(*T)->lchild); /* 递归构造左子树 */
		if((*T)->lchild) /* 有左孩子 */
			(*T)->LTag=Link;
		CreateBiThrTree(&(*T)->rchild); /* 递归构造右子树 */
		if((*T)->rchild) /* 有右孩子 */
			(*T)->RTag=Link;
	}
	return OK;
}

BiThrTree pre; /* 全局变量,始终指向刚刚访问过的结点 */
/* 中序遍历进行中序线索化 */
void InThreading(BiThrTree p)
{
	if(p)
	{
		InThreading(p->lchild); /* 递归左子树线索化 */
		if(!p->lchild) /* 没有左孩子 */
		{
			p->LTag=Thread; /* 前驱线索 */
			p->lchild=pre; /* 左孩子指针指向前驱 */
		}
		if(!pre->rchild) /* 前驱没有右孩子 */
		{
			pre->RTag=Thread; /* 后继线索 */
			pre->rchild=p; /* 前驱右孩子指针指向后继(当前结点p) */
		}
		pre=p; /* 保持pre指向p的前驱 */
		InThreading(p->rchild); /* 递归右子树线索化 */
	}
}

/* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点 */
Status InOrderThreading(BiThrTree *Thrt,BiThrTree T)
{
	*Thrt=(BiThrTree)malloc(sizeof(BiThrNode));
	if(!*Thrt)
		exit(OVERFLOW);
	(*Thrt)->LTag=Link; /* 建头结点 */
	(*Thrt)->RTag=Thread;
	(*Thrt)->rchild=(*Thrt); /* 右指针回指 */
	if(!T) /* 若二叉树空,则左指针回指 */
		(*Thrt)->lchild=*Thrt;
	else
	{
		(*Thrt)->lchild=T;
		pre=(*Thrt);
		InThreading(T); /* 中序遍历进行中序线索化 */
		pre->rchild=*Thrt;
		pre->RTag=Thread; /* 最后一个结点线索化 */
		(*Thrt)->rchild=pre;
	}
	return OK;
}

/* 中序遍历二叉线索树T(头结点)的非递归算法 */
Status InOrderTraverse_Thr(BiThrTree T)
{
	BiThrTree p;
	p=T->lchild; /* p指向根结点 */
	while(p!=T)
	{ /* 空树或遍历结束时,p==T */
		while(p->LTag==Link)
			p=p->lchild;
		if(!visit(p->data)) /* 访问其左子树为空的结点 */
			return ERROR;
		while(p->RTag==Thread&&p->rchild!=T)
		{
			p=p->rchild;
			visit(p->data); /* 访问后继结点 */
		}
		p=p->rchild;
	}
	return OK;
}

int main()
{
	BiThrTree H,T;
	printf("请按前序输入二叉树(如:'ABDH##I##EJ###CF##G##')\n");
 	CreateBiThrTree(&T); /* 按前序产生二叉树 */
	InOrderThreading(&H,T); /* 中序遍历,并中序线索化二叉树 */
	printf("中序遍历(输出)二叉线索树:\n");
	InOrderTraverse_Thr(H); /* 中序遍历(输出)二叉线索树 */
	printf("\n");

	return 0;
}

结果:

适用范围:

如果所用的二叉树需要经常遍历或查找结点时需要某种遍历序列中的前驱和后继,那么采用线索二叉链表的存储结构将会是不错的选择。

时间: 2024-10-05 11:50:52

【数据结构】线索二叉树的相关文章

(原)数据结构——线索二叉树

原文地址:http://www.cnblogs.com/Security-Darren/p/4716082.html 转载务必注明出处! 线索二叉树的思想来源于二叉树的存储结构中,存在一些空的指针域,因此是否能够将这些空间利用起来,存储一些关于节点间先后顺序的信息,由此产生了线索二叉树.线索二叉树中,线索反映前驱.后继的关系,而指针则体现左右子树. 以二叉链表为例,线索二叉树存储结构上的特点是添加标识符,表明左右指针域究竟存的是指向前驱和后继的线索,还是指向左右子树的指针: 线索二叉树的优势是一

数据结构 - 线索二叉树

线索树 遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作. 如何找到遍历过程中动态得到的每个结点的直接前驱和直接后继(第一个和最后一个除外)?如何保存这些信息? 问:一棵有n个结点的二叉树,有多少个空闲指针域未用? 若一棵二叉树有n个结点,则有n-1条指针连线 , 而n个结点共有2n个指针域(Lchild和Rchild) ,所以有n+1个空闲指针域未用. 可以利用这些空闲的指针域来存放结点的直接前驱和直接后继信息. 对结点的指针域做如下规定: ◆ 若结点有左孩

数据结构 线索二叉树 原理及实现

通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数.准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个.如下图所示. 因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点.这种指针称为线索. 记ptr指向二叉链表中的一个结点,以下是建立线索的规则: (1)如果ptr->lchild为空,则存放指向中序遍历序列中该结点的前驱结点.这个结点称为ptr的中序前驱: (2)如果ptr->rchild为空,则存放指向中序遍历

重拾算法(2)——线索二叉树

重拾算法(2)——线索二叉树 上一篇我们实现了二叉树的递归和非递归遍历,并为其复用精心设计了遍历方法Traverse(TraverseOrder order, NodeWorker<T> worker);今天就在此基础上实现线索二叉树. 什么是线索二叉树 二叉树中容易找到结点的左右孩子信息,但该结点在某一序列中的直接前驱和直接后继只能在某种遍历过程中动态获得. 先依遍历规则把每个结点某一序列中对应的前驱和后继线索预存起来,这叫做"线索化". 意义:从任一结点出发都能快速找到

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

遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作.如何找到遍历过程中动态得到的每个结点的直接前驱和直接后继(第一个和最后一个除外)?如何保存这些信息? 设一棵二叉树有n个结点,则有n-1条边(指针连线) , 而n个结点共有2n个指针域(Lchild和Rchild) ,显然有n+1个空闲指针域未用.则可以利用这些空闲的指针域来存放结点的直接前驱和直接后继信息. 对结点的指针域做如下规定: 1.若结点有左子树,则其leftChild域指示其左孩子,否则令leftC

数据结构(三):非线性逻辑结构-特殊的二叉树结构:堆、哈夫曼树、二叉搜索树、平衡二叉搜索树、红黑树、线索二叉树

在上一篇数据结构的博文<数据结构(三):非线性逻辑结构-二叉树>中已经对二叉树的概念.遍历等基本的概念和操作进行了介绍.本篇博文主要介绍几个特殊的二叉树,堆.哈夫曼树.二叉搜索树.平衡二叉搜索树.红黑树.线索二叉树,它们在解决实际问题中有着非常重要的应用.本文主要从概念和一些基本操作上进行分类和总结. 一.概念总揽 (1) 堆 堆(heap order)是一种特殊的表,如果将它看做是一颗完全二叉树的层次序列,那么它具有如下的性质:每个节点的值都不大于其孩子的值,或每个节点的值都不小于其孩子的值

【算法与数据结构】二叉树 中序线索

中序线索二叉树 /************************************************************************ 线索二叉树 二叉树的节点有五部分构造 ----------------------------------------- | lChild | lTag | value | rTag | rChild | ----------------------------------------- lChild = (lTag == 0 ? 左

【数据结构】中序遍历线索二叉树

昨天写了个二叉树遍历,自以为对二叉树很了解了.自大的认为线索二叉树不过是加了点线索而已,不足挂齿.可是当真的自己编程序写的时候才发现完全不是那么容易.在有线索的情况下,如何判别Link类型的下一节点,如何不用栈跳过已访问节点搞得脑子晕晕的. 折腾一个晚上,才根据书上把线索二叉树的建立.中序遍历给写出来.要回去继续好好的理清关系. #include <stdio.h> #include <stdlib.h> typedef enum PointerTag{Link, Thread};

数据结构与算法(八)-二叉树(斜二叉树、满二叉树、完全二叉树、线索二叉树)

前言:前面了解了树的概念和基本的存储结构类型及树的分类,而在树中应用最广泛的种类是二叉树 一.简介 在树型结构中,如果每个父节点只有两个子节点,那么这样的树被称为二叉树(Binary tree).其中,一个父结点的两个字节点分别叫做“左子节点”和“右子节点”.不过也不是所有父节点都有两个子节点,只有左子节点或者只有右子节点的情况也存在.另外,也会存在叶子结点,也就是一个子节点都没有的节点,唯一的限制就是每一个节点的子节点不能超过两个. 之前谈过的单向链表,是一种通过“指向下一个元素的指针”来连接

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

//线索二叉树,这里在二叉树的基础上增加了线索化 //杨鑫 #include <stdio.h> #include <stdlib.h> typedef char ElemType; typedef enum {Link,Thread} childTag; //Link表示结点.Thread表示线索 typedef struct bitNode { ElemType data; struct bitNode *lchild, *rchild; int ltag, rtag; } b