线索thread二叉树

对于一个普通的二叉树

我们可以很明显的看到,在一个二叉树中,会有许多的空结点,而这些空结点必然会造成空间的浪费,为了解决这个问题,我们可以引入线索二叉树,把这些空结点利用起来,利用 ‘^’ 记录给定结点的前驱后继,那么问题就来了,该如何建立呢?

前面我们说过四种的遍厉方法,我应该用哪种方法来建立线索二叉树呢?

经过逐一的分析,我们发现利用中序遍历方法能够有效地建立起线索二叉树

我们先看一看在上述二叉树中中序遍历的结果

H D I B E A F C G

红色的结点为有空结点

在空结点中储存前驱与后继

单面对这样的一种二叉树时又怎么办呢?

中序遍历为

F D G B A C E

我们可以看到在b结点与结点 c出只有一个空结点

那机器该如何判断放的是线索还是指针呢?

为了解决这种问题,我们可以吧树的每个结点进行扩容

ltag : 为0时,表示lchild指向改结点的左孩子; 为1时,表示lchild指向该结点的前驱

rtag:为0时,表示rchild指向该结点的右孩子;为1时,表示rchild指向该结点的后继

线索二叉树的代码实现:

#include<iostream>
using namespace std;

typedef char ElemType;

//线索存储标志位
//Link 为0时,表示指向左右孩子的指针
//Thread  为1时,表示指向前驱后继的线索
typedef enum{Link, Thread} PointerTag;

typedef struct BitThrNode
{
	char data;
	struct BitThrNode *lchild, *rchild;
	PointerTag ltag;
	PointerTag rtag;
}BitThrNode, *BitThrTree;

//全局变量,指向刚刚访问过的节点
BitThrTree pre;

//利用前序遍历创建二叉树
void createBitThrTree(BitThrTree *T) //根节点的地址
{
	char c;
	cin >> c;
	if(c ==‘-‘)
	{
		*T=NULL;
	}
	else
	{
		*T=new BitThrNode;
	    (*T)->data=c;
		(*T)->ltag=Link;
		(*T)->rtag=Link;
		createBitThrTree(&(*T)->lchild);
		createBitThrTree(&(*T)->rchild);
	}
}

//中序遍历线索化
void InThreading(BitThrTree T)
{
	if(T)
	{
		InThreading(T->lchild);//递归左孩子线索化
		//结点处理
		if(!T->lchild)
		{
			T->ltag=Thread;
			T->lchild=pre;
		}

		if(!pre->rchild)
		{
			pre->rtag=Thread;
			pre->rchild=T;
		}

		pre=T;

		InThreading(T->rchild);//递归右孩子线索化
	}
}

void InorderThreading(BitThrTree *p, BitThrTree T)
{
	*p=new BitThrNode();
    (*p)->ltag=Link;
	(*p)->rtag=Thread;
	(*p)->rchild=*p;
	if(!T)
	{
		(*p)->lchild=*p;
	}
	else
	{
		(*p)->lchild=T;
		pre=*p;
		InThreading(T);
	    pre->rchild=*p;
		pre->rtag=Thread;
		(*p)->rchild=pre;
	}
}

void visit(char c)
{
	cout<<c<<endl;
}

//中序遍历二叉树非递归
void InorderTravel(BitThrTree T)
{
	BitThrTree p;
	p=T->lchild;
	while(p!=T)
	{
		while(p->ltag==Link)
		{
			p=p->lchild;
		}
		visit(p->data);

		while(p->rtag==Thread&&p->rchild!=T)
		{
			p=p->rchild;
			visit(p->data);
		}
		p=p->rchild;
	}
}

int main()
{
	BitThrTree T=NULL;
	BitThrTree p;
	createBitThrTree(&T);
        InorderThreading(&p,T);

	cout<<"中序遍历输出结果为"<<endl;
	InorderTravel(p);

        return 0;
}

  

时间: 2024-10-08 22:02:44

线索thread二叉树的相关文章

数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树

[本文谢绝转载,原文来自http://990487026.blog.51cto.com] 树 数据结构与算法 3:二叉树,遍历,创建,释放,拷贝,求高度,面试,线索树 二叉树的创建,关系建立 二叉树的创建,关系建立2 三叉链表法 双亲链表: 二叉树的遍历 遍历的分析PPT 计算二叉树中叶子节点的数目:使用全局变量计数器 计算二叉树中叶子节点的数目:不使用全局变量计数器 无论是先序遍历,中序遍历,后序遍历,求叶子的数字都不变;因为本质都是一样的,任何一个节点都会遍历3趟 求二叉树的高度 二叉树的拷

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

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

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

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

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

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

彻底理解线索二叉树

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

二叉树的层序遍历和二叉树的线索化

先根,后子树:先左子树,后右子树 二叉树的根节点 a 入队 a 的子树,根节点 b 和 c 分别入队 然后 b 的子树的根节点入队(为空) c 的子树的根节点入队 d 的子树的根节点入队(为空) e 的子树的根节点入队 f 的子树的根节点入队(为空) g的子树的根节点入队(为空)结束层序遍历,整个过程就是一层层的遍历,依靠一个队列来存放临时查找的结点. 二叉树线索化 问题的提出:当以二叉链表作为存储结构时,只能找到结点的左右孩子的信息,而不能直接找到结点的任一序列的前驱与后继信息,这种信息只有在

数据结构 - 线索二叉树

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

二叉树之线索二叉树

相对于顺序存储结构而言,利用链式存储结构的二叉树已经有了很高的存储效率,单是还是有空间上未利用到的地方,比如说叶子结点的左右孩子是空的,指向左右孩子的指针就是空闲的,没有被利用到:而且,有时候给定一个结点,我们需要查找该结点的前驱结点和后继结点,如果按照中序遍历的做法去查找的话,对于一个非叶子结点,其前驱和后继结点查找可以以下算法: 1.preNode=node.left;//前去结点就是该结点的左孩子 2.subNode=search(node.right)://后继结点是该结点的右子树的最左

线索二叉树的实现

<span style="font-size:18px;">/* 1.二叉树遍历算法提供了二叉树的一次性遍历,可是二叉树遍历算法无法实现用户程序像分步 遍历单链表那样分步遍历二叉树.线索二叉树就是专门为实现分步遍历二叉树而设计的.线索二叉树能够实现像双向 链表那样,既能够从前向后分步遍历二叉树,又能够从后向前分步遍历二叉树 2.当按某种规则遍历二叉树时,保存遍历时得到的节点的后继节点信息和前驱节点信息的最经常使用的方法是建立线索二叉树 3.线索二叉树的规定:当某节点的左指针