6.3线索二叉树(二叉树的线索化)

6.3线索二叉树(二叉树的线索化)

问题引入:以二叉链表作为存储结构时,只能得到结点的左、右孩子的信息,不能得到直接前驱、后继的信息。

问题解决:将二叉树线索化。

实现原理:n个结点的二叉树具有n+1个空指针域,利用这些空指针域存储结点的前驱、后继信息。

实质:线索化的实质是将二叉链表中的空指针改为指向前驱、后继的线索。

(1)二叉树的存储表示

enum {link,thread};//link=0; thread=1;
typedef struct bintree
{
	char data;
	struct bintree *lchild, *rchild;
	int ltag,rtag;//标志域。指示 指针或线索
}BiNode, *BiTree;

(2)二叉树的创建

6.1二叉树的创建章节。

(3)中序线索化 及 遍历(注意注释内容)

BiTree inorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);//建立头指针
	if(!thrt)
		exit(0);
	thrt->rtag = thread;//右指针回指
	thrt->rchild = thrt;
	thrt->ltag = link;
	if(!t)//若二叉树空,左指针回指
		thrt->lchild = thrt;
	else
	{
		thrt->lchild = t;
		pre = thrt;

		in_threading(t);//中序遍历进行中序线索化

		pre->rtag = thread;//最后一个节点线索化
		pre->rchild = thrt;
		thrt->rchild = pre;
	}
	return thrt;
}
void in_threading(BiTree p)
{
	if(p)
	{
		in_threading(p -> lchild);//左子树线索化
		if(! p->lchild)//前驱线索
		{
			p->ltag = thread;
			p->lchild = pre;
		}
		if(! pre->rchild)//后继线索
		{
			pre->rtag = thread;
			pre->rchild = p;
		}
		pre = p;//保持pre指向 p 的前驱
		in_threading(p->rchild);//右子树线索化
	}
}
void inorder_traverse(BiTree thrt)
{
	BiTree p = thrt->lchild;
	while(p != thrt)//空树或遍历结束时,p==thrt
	{
		while(p->ltag == link)
		{
			p = p->lchild;
		}
		printf("%c ",p->data);
		if(p->rtag == thread && p->rchild != thrt)
		{
			p = p->rchild;
			printf("%c ",p->data);
		}
		p = p->rchild;
	}
}

(4)先序线索化 及 遍历

BiTree preorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);
	if(! thrt)
		exit(0);
	thrt -> rtag = thread;
	thrt -> rchild = thrt;
	thrt -> ltag = link;

	if(!t)
		thrt -> lchild = thrt;
	else
	{
		thrt -> lchild = t;
		pre = thrt;

		pre_threading(t);

		pre -> rtag = thread;
		pre -> rchild = thrt;
		thrt -> rchild = pre;
	}
	return thrt;
}
void pre_threading(BiTree p)
{
	if(p)
	{
		if(! p->lchild)
		{
			p -> ltag = thread;
			p -> lchild = pre;
		}
		if(!p -> rchild)
			p -> rtag = thread;
		if(pre && pre->rtag == thread)
			pre -> rchild = p;
		pre = p;
		if(p->ltag == link)
			pre_threading(p -> lchild);
		if(p->rtag == link)
			pre_threading(p -> rchild);
	}
}
void preorder_traverse(BiTree thrt)
{
	BiTree p = thrt -> lchild;

	printf("%c ",p->data);
	while(p->rchild != thrt)
	{
		if(p->ltag == link)
			p = p->lchild;
		else
			p = p->rchild;

		printf("%c ",p->data);
	}
}

(5)后序线索化 及 遍历

BiTree postorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);
	if(! thrt)
		exit(0);
	thrt -> rtag = thread;
	thrt -> rchild = thrt;
	thrt -> ltag = link;

	if(!t)
		thrt -> lchild = thrt;
	else
	{
		thrt -> lchild = t;
		pre = thrt;

		post_threading(t);

		pre -> rtag = thread;
		pre -> rchild = thrt;
		thrt -> rchild = pre;
	}
	return thrt;
}
void post_threading(BiTree p)
{
	if(p)
	{
		post_threading(p->lchild);   //左子树线索化
        post_threading(p->rchild);   //右子树线索化
		if(!p->lchild)
		{
			p->ltag=thread;
			p->lchild=pre;
		}
		if(!pre->rchild)
		{
			pre->rtag=thread;
			pre->rchild=p;
		}
		pre=p;
	}
}
void postorder_traverse(BiTree thrt)
{
	BiTree p = thrt;

	while(p->ltag==link||p->rtag==link)   //有左孩子先访问左孩子,没有左孩子先访问右孩子
	{
		while(p->ltag==link)
			p=p->lchild;
		if(p->rtag==link)                //访问左孩子为空的结点的右孩子
			p=p->rchild;
	}
	printf("%c ",p->data);
	while(p!=T)                        //p不为根结点
	{
		if(p->rtag==link)              //若p是有兄弟的左孩子
		{
			if(pre->rtag==thread||p==pre->rchild) //若p是双亲的右孩子或是独生左孩子,则后继为双亲
				p=pre;
			else
			{
				p=pre->rchild;              //后继为双亲的右子树上按照后序遍历访问的第一个结点。
				while(p->ltag==link||p->rtag==link)
				{
					while(p->ltag==link)
						p=p->lchild;
					if(p->rtag==link)
						p=p->rchild;
			    }
			}
		}
		else
			p=p->rchild;             //p指向后继

		printf("%c ",p->data);
	}
}

(6)总程序源代码(.c)

					/*  样例输入: abc##de#g##f###  */
# include <stdio.h>
# include <stdlib.h>
# define len (sizeof(BiNode))
# define OK 1

enum {link,thread};
typedef struct bintree
{
	char data;
	struct bintree *lchild, *rchild;
	int ltag,rtag;
}BiNode, *BiTree;

BiTree T, thrt, pre;

int bintree_creat(BiTree *q);
void welcome(BiTree t);

BiTree preorder_threading(BiTree thrt,BiTree t);//先序
void pre_threading(BiTree p);
void preorder_traverse(BiTree thrt);

BiTree inorder_threading(BiTree thrt,BiTree t);//中序
void in_threading(BiTree p);
void inorder_traverse(BiTree thrt);

BiTree postorder_threading(BiTree thrt,BiTree t);//后序
void post_threading(BiTree p);
void postorder_traverse(BiTree thrt);

int main()
{
	printf("now create the bintree first,please input :\n");
	bintree_creat(&T);

	welcome(T);

	return 0;
}

int bintree_creat(BiTree *q)
{
	char ch;
	ch=getchar();

	if(ch=='#')
		(*q)=NULL;
	else
	{
		(*q) = (BiTree )malloc(len);
		if((*q))
		{
			(*q)->data = ch;
			(*q)->ltag = link;
			(*q)->rtag = link;
			bintree_creat(&(*q) -> lchild);
			bintree_creat(&(*q) -> rchild);
		}
	}

	return OK;
}

void welcome(BiTree t)
{
	int i;
	printf("input 1 :preorder_threading the bintree .\n");
	printf("input 2 :inorder_threading the bintree .\n");
	printf("input 3 :postorder_threading the bintree .\n\n");
	scanf("%d",&i);

	switch (i)
	{
		case 1 :thrt = preorder_threading(thrt,t);
				preorder_traverse(thrt);
				printf("\n\n"); break;

		case 2 :thrt = inorder_threading(thrt,t);
				inorder_traverse(thrt);
				printf("\n\n"); break;

		case 3 :thrt = postorder_threading(thrt,t);
				postorder_traverse(thrt);
				printf("\n\n"); break;

		default :printf("input error !");
				 exit(1);
	}
}

BiTree preorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);
	if(! thrt)
		exit(0);
	thrt -> rtag = thread;
	thrt -> rchild = thrt;
	thrt -> ltag = link;

	if(!t)
		thrt -> lchild = thrt;
	else
	{
		thrt -> lchild = t;
		pre = thrt;

		pre_threading(t);

		pre -> rtag = thread;
		pre -> rchild = thrt;
		thrt -> rchild = pre;
	}
	return thrt;
}
void pre_threading(BiTree p)
{
	if(p)
	{
		if(! p->lchild)
		{
			p -> ltag = thread;
			p -> lchild = pre;
		}
		if(!p -> rchild)
			p -> rtag = thread;
		if(pre && pre->rtag == thread)
			pre -> rchild = p;
		pre = p;
		if(p->ltag == link)
			pre_threading(p -> lchild);
		if(p->rtag == link)
			pre_threading(p -> rchild);
	}
}
void preorder_traverse(BiTree thrt)
{
	BiTree p = thrt -> lchild;

	printf("%c ",p->data);
	while(p->rchild != thrt)
	{
		if(p->ltag == link)
			p = p->lchild;
		else
			p = p->rchild;

		printf("%c ",p->data);
	}
}

BiTree inorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);//建立头指针
	if(!thrt)
		exit(0);
	thrt->rtag = thread;//右指针回指
	thrt->rchild = thrt;
	thrt->ltag = link;
	if(!t)//若二叉树空,左指针回指
		thrt->lchild = thrt;
	else
	{
		thrt->lchild = t;
		pre = thrt;

		in_threading(t);//中序遍历进行中序线索化

		pre->rtag = thread;//最后一个节点线索化
		pre->rchild = thrt;
		thrt->rchild = pre;
	}
	return thrt;
}
void in_threading(BiTree p)
{
	if(p)
	{
		in_threading(p -> lchild);//左子树线索化
		if(! p->lchild)//前驱线索
		{
			p->ltag = thread;
			p->lchild = pre;
		}
		if(! pre->rchild)//后继线索
		{
			pre->rtag = thread;
			pre->rchild = p;
		}
		pre = p;//保持pre指向 p 的前驱
		in_threading(p->rchild);//右子树线索化
	}
}
void inorder_traverse(BiTree thrt)
{
	BiTree p = thrt->lchild;
	while(p != thrt)//空树或遍历结束时,p==thrt
	{
		while(p->ltag == link)
		{
			p = p->lchild;
		}
		printf("%c ",p->data);
		if(p->rtag == thread && p->rchild != thrt)
		{
			p = p->rchild;
			printf("%c ",p->data);
		}
		p = p->rchild;
	}
}

BiTree postorder_threading(BiTree thrt,BiTree t)
{
	thrt = (BiTree )malloc(len);
	if(! thrt)
		exit(0);
	thrt -> rtag = thread;
	thrt -> rchild = thrt;
	thrt -> ltag = link;

	if(!t)
		thrt -> lchild = thrt;
	else
	{
		thrt -> lchild = t;
		pre = thrt;

		post_threading(t);

		pre -> rtag = thread;
		pre -> rchild = thrt;
		thrt -> rchild = pre;
	}
	return thrt;
}
void post_threading(BiTree p)
{
	if(p)
	{
		post_threading(p->lchild);   //左子树线索化
        post_threading(p->rchild);   //右子树线索化
		if(!p->lchild)
		{
			p->ltag=thread;
			p->lchild=pre;
		}
		if(!pre->rchild)
		{
			pre->rtag=thread;
			pre->rchild=p;
		}
		pre=p;
	}
}
void postorder_traverse(BiTree thrt)
{
	BiTree p = thrt;

	while(p->ltag==link||p->rtag==link)   //有左孩子先访问左孩子,没有左孩子先访问右孩子
	{
		while(p->ltag==link)
			p=p->lchild;
		if(p->rtag==link)                //访问左孩子为空的结点的右孩子
			p=p->rchild;
	}
	printf("%c ",p->data);
	while(p!=T)                        //p不为根结点
	{
		if(p->rtag==link)              //若p是有兄弟的左孩子
		{
			if(pre->rtag==thread||p==pre->rchild) //若p是双亲的右孩子或是独生左孩子,则后继为双亲
				p=pre;
			else
			{
				p=pre->rchild;              //后继为双亲的右子树上按照后序遍历访问的第一个结点。
				while(p->ltag==link||p->rtag==link)
				{
					while(p->ltag==link)
						p=p->lchild;
					if(p->rtag==link)
						p=p->rchild;
			    }
			}
		}
		else
			p=p->rchild;             //p指向后继

		printf("%c ",p->data);
	}
}

(7)撰写匆忙,表述简陋,必有疏漏。欢迎朋友们批评指正。

2014/10/21

时间: 2024-11-05 11:34:53

6.3线索二叉树(二叉树的线索化)的相关文章

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

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

二叉树 二叉树的性质 存储结构 遍历二叉树 C实现二叉树的创建和遍历 线索二叉树

定义 二叉树(binary tree)是n(n>=0)个结点的有限集合,该集合为空集合称为空二叉树,或者有一个根结点和两棵互不相交的,分别称为树根结点的左孩子树和右孩子树组成. 二叉树的特点 每个结点最多有两棵子树,所以二叉树总没有度大于2的结点 左子树和右子树是有顺序的,次数不能任意颠倒 即使树中某结点只有一棵子树,也要区分是左子树还是右子树 特殊的二叉树 1. 斜树 所有的结点都只有左子树的二叉树称为左斜树; 所有的结点都只有右子树的二叉树称为右斜树; 这两者统称为斜树 2. 满二叉树 在一

javascript实现数据结构: 树和二叉树,二叉树的遍历和基本操作

树型结构是一类非常重要的非线性结构.直观地,树型结构是以分支关系定义的层次结构. 树在计算机领域中也有着广泛的应用,例如在编译程序中,用树来表示源程序的语法结构:在数据库系统中,可用树来组织信息:在分析算法的行为时,可用树来描述其执行过程等等. 下面讲解的内容完整代码在这:https://github.com/LukeLin/data-structure-with-js/blob/master/Binary%20tree/BinaryTree.js 首先看看树的一些概念: 1.树(Tree)是n

5)二叉树中序线索化

1 #include "iostream" 2 #include "stdlib.h" 3 using namespace std; 4 5 typedef char type; 6 struct bnode{ 7 type data; 8 bnode *lchild,*rchild; 9 int rtag,ltag; 10 }; 11 12 const int lrtag = 0; 13 class thbtree{ 14 public: 15 thbtree()

线索thread二叉树

对于一个普通的二叉树 我们可以很明显的看到,在一个二叉树中,会有许多的空结点,而这些空结点必然会造成空间的浪费,为了解决这个问题,我们可以引入线索二叉树,把这些空结点利用起来,利用 '^' 记录给定结点的前驱后继,那么问题就来了,该如何建立呢? 前面我们说过四种的遍厉方法,我应该用哪种方法来建立线索二叉树呢? 经过逐一的分析,我们发现利用中序遍历方法能够有效地建立起线索二叉树 我们先看一看在上述二叉树中中序遍历的结果 H D I B E A F C G 红色的结点为有空结点 在空结点中储存前驱与

P1040 加分二叉树(树上记忆化搜素)

这道题很水 但我没做出来……………………………… 我写的时候状态设计错了,设计dp[l][m][r]为从l到r以m为根的值 这样写遍历状态就是n^3的,会TLE. 而且写路径的时候是用结构体写的,这样会错,应该用root[l][r]表示从l到r的根 对于l到r,枚举根在哪就好了 总结 (1)状态设计,学会简洁的设计状态 (2)路径输出,可以开和dp数组一样的数组,在dp数组更新的时候路径数组也更新 (3)在非线性结构上做dp的时候(如树),用记忆化搜索会比递推方便. #include<bits/

数据结构-王道2017-第4章 树与二叉树-二叉树的遍历

typedef int ElemType; typedef struct BitNode { ElemType data; //数据域 struct BitNode *lchild, *rchild; //左右孩子指针 }BitNode,*BitTree; void visit(BitNode *b) { printf("%d ", b->data); } //无论采用哪种遍历方法,时间复杂度都是O(n),因为每个结点都访问一次且仅访问一次,递归工作栈的栈深恰好为树的深度,空间复

数和二叉树——二叉树的建立及应用(遍历等)(基础篇)

二叉树:二叉树是每个结点最多有两个子树的有序树. 先来介绍一下二叉树的一些基本性质吧~ 二叉树的性质: 1.非空二叉树上叶子结点数等于双分支节点数加一. 性质1 二叉树第i层上的结点数目最多为2i-1(i≥1).证明:用数学归纳法证明:     归纳基础:i=1时,有2i-1=20=1.因为第1层上只有一个根结点,所以命题成立.    归纳假设:假设对所有的j(1≤j<i)命题成立,即第j层上至多有2j-1个结点,证明j=i时命题亦成立.    归纳步骤:根据归纳假设,第i-1层上至多有2i-2

DS二叉树——二叉树之数组存储

二叉树可以采用数组的方法进行存储,把数组中的数据依次自上而下,自左至右存储到二叉树结点中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点就在数组中用0来表示.,如下图所示 从上图可以看出,右边的是一颗普通的二叉树,当它与左边的完全二叉树对比,发现它比完全二叉树少了第5号结点,所以在数组中用0表示,同样它还少了完全二叉树中的第10.11号结点,所以在数组中也用0表示.结点存储的数据均为非负整数 输入 第一行输入一个整数t,表示有t个二叉树 第二行起,每行输入一个数组,先输入数组长度,再输入数组

DS二叉树--二叉树之父子结点

题目描述 给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符'0'表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构. 编写程序输出该树的所有叶子结点和它们的父亲结点 输入 第一行输入一个整数t,表示有t个二叉树 第二行起,按照题目表示的输入方法,输入每个二叉树的先序遍历,连续输入t行 输出 第一行按先序遍历,输出第1个示例的叶子节点 第二行输出第1个示例中与叶子相对应的父亲节点 以此类推输出其它示例的结果 样例输入 3 AB0C00D00 AB00C00 ABCD0000