首页 > 其他 > 详细

实战数据结构(12)_二叉树的线索化

时间:2014-03-28 18:43:16      阅读:510      评论:0      收藏:0      [点我收藏+]
     二叉树的线索化,花了点时间去整理。整个递归过程还是有些抽象的。为什么要进行二叉树的线索化,目的就是为了节省使用二叉链表实现过程中,太多的NULL指针。如果把这些空指针都利用起来,串起来一个循环双向链表,那么对于查找是非常方便的。对于查找而言,如中序遍历,我们关心的是一个节点的后继节点和前驱节点。
因为对于未线索化的二叉树而言,只能从某个节点来获取它的左右孩子节点,也就说只能置顶向下,而不能同过节点快速找到其前驱节点,如果要获取的话,又要遍历一次。
     所以,线索化,就能清楚的知道某个节点的前驱和后继节点,这样将那些空余的节点利用起来了,而且查找也方便了。
下面就是代码的实现:
(1) 线索二叉树的数据结构
(2) 创建二叉树,并且线索化
(3)线索化的二叉树的遍历,注意不能使用递归了。
(4)线索化的二叉树的查找。

/***********************************************************************
二叉树的线索化
(1)创建二叉树(按照带括号的字符串)
(2)二叉树的线索化
(3)二叉树线索化后遍历
(4)查找某个值的 先驱节点
(5)查找某个值的 后继节点
************************************************************************/
#include <cstdio>

typedef enum {Link,Thread} PointFlag; //定义枚举量 pointflag为二者之一
typedef struct Node
{
	char ch;							// 数据域
	struct Node *plchild,*prchild;		// 左右节点指针
	PointFlag lflag,rflag;				// 标志位 link为 连接 thread为线索标志
}BiTreeNode;
const int MAX=20;
//按照字符串创建 A(B(,D(G)),C(E(,H),F))  16:30
void CreateBiTree_ByString(BiTreeNode * &T,char str[])
{
	BiTreeNode *p=NULL;
	int flag=0,top=0;//flag=1左孩子,flag=2右孩子 top为栈量
	BiTreeNode *Stack[MAX];	//栈 用于存父节点
	while(*str)
	{
		switch(*str)
		{
			case ‘(‘: //则刚创建的节点为 父节点入栈
				Stack[top++]=p;
				flag=1;
				break;
			case ‘,‘:
				flag=2;
				break;
			case ‘)‘:
				top--;	//构造完毕了栈顶节点的左右孩子 出栈
				break;
			default:
				p=new BiTreeNode ;
				if(NULL==p)	return ;
				p->ch=*str;
				p->plchild=p->prchild=NULL;
				p->lflag=p->rflag=Link;
				if(T==NULL)		//创建根节点
					T=p;
				else
				{	
					switch(flag)
					{
						case 1:
							Stack[top-1]->plchild=p; //p为左孩子
							break;
						case 2:
							Stack[top-1]->prchild=p; //p为右孩子
							break;
					}
				/*	if(Stack[top-1]->plchild)
						Stack[top-1]->lflag=Link;
					if(Stack[top-1]->prchild)
						Stack[top-1]->rflag=Link;*/
				}
				break;
		}
		++str;
	}
}
void LDR_Traverse(BiTreeNode *T)
{
	if(T)
	{	
		LDR_Traverse(T->plchild);
		printf("%2c",T->ch);
		LDR_Traverse(T->prchild);
	}
}

BiTreeNode *g_pre;	//全局

/***********************************************************************
二叉树进行中序遍历线索化
难点:写法上和中序遍历一样。先不断的访问左子树的最左节点(中序的思路)
	  那么如何进行前驱和后继节点的连接呢? 
前驱: 是完成当前指针p的前驱
后继:是完成之前节点的后继
***********************************************************************/
void LDR_Traverse_Thread(BiTreeNode *p)
{
	if(p)
	{
		LDR_Traverse_Thread(p->plchild); //将左子树线索化
		if(p->plchild==NULL)	//一直遍历到最左子节点 叶子节点或者只有右子树
		{	//p更新 前驱节点
			p->lflag=Thread;	//p的左孩子节点 标志为 前驱
			p->plchild=g_pre;	// g_pre保存为上一个访问的节点(按照中序遍历顺序)
		}
		if(g_pre->prchild==NULL) //
		{	
			g_pre->rflag=Thread;
			g_pre->prchild=p;
		}
		g_pre=p;	//p已经遍历过 pre指向刚遍历过的节点
		LDR_Traverse_Thread(p->prchild);
	}
}
//二叉树的线索化
BiTreeNode* BiTreeThread(BiTreeNode*  &T)
{	
	//构造头结点
	BiTreeNode *p=new BiTreeNode;
	if(!p || !T)	return NULL;
	
	//头节点处理
	p->lflag=Link;
	p->rflag=Thread;
	p->plchild=T;	//头结点左孩子 指向根节点
	p->prchild=p;	//头结点右孩子 指向自己
	
	g_pre=p;		//g_pre初始化 指向头节点
	LDR_Traverse_Thread(T);	//将T树进行线索化
	
	//最后一个节点处理
	g_pre->rflag=Thread;	//最后一个节点 标志位
	g_pre->prchild=p;		//最后一个节点 后继指向头节点
	p->prchild=g_pre;		//头节点后继为 最后一个节点
	
	return p;	//返回头节点
}

//中序非递归 遍历线索化 后
void LDR_Travese_AfterThread(BiTreeNode *T)
{
	BiTreeNode *p=T->plchild; //p为根节点
	while(p!=T)
	{
		while(p->lflag==Link)
			p=p->plchild;
		printf("%2d %2c %2d \n",p->lflag,p->ch,p->rflag);
		while(p->rflag==Thread && p->prchild !=T) //如果 p有后继节点则 直接通过后继节点访问下一个 节点
		{
			p=p->prchild;
			printf("%2d %2c %2d \n",p->lflag,p->ch,p->rflag);
		}
		p=p->prchild;
	}
}
//找到指定节点的前驱节点
BiTreeNode *FindPointNode(BiTreeNode *Head,char key)
{
	BiTreeNode *p=Head->plchild; //获取根节点
	while(p!=Head)
	{
		while(p->lflag==Link)
			p=p->plchild;
		if(p->ch== key)
			return p;
		while(p->rflag == Thread && p->prchild !=Head )
		{
			p=p->prchild;
			if(p->ch == key)
				return p;
		}
		p=p->prchild;
	}
	return NULL;
}	
//找到指定节点的后继节点
//就是根据 rflag==1直接找到,后者去找该节点右子树最左节点
BiTreeNode *FindNextNode(BiTreeNode *p)
{	
	BiTreeNode *pre=NULL;
	if(p->rflag==Thread)
		return p->prchild;
	else {
		pre=p->prchild;
		while(pre->lflag==Link)
			pre=pre->plchild;
		return pre;
	}
}
//找指定节点的前驱节点
//如果该节点的lflag==1直接返回,否则就找到该节点的左子树的最右节点
BiTreeNode *FindPreNode(BiTreeNode *p)
{
	BiTreeNode *pre=NULL;
	if(p->lflag==Thread)
		return p->plchild;
	else {
		pre=p->plchild;
		while(pre->rflag==Link)
			pre=pre->prchild;
		return pre;
	}
}
int main()
{	
	BiTreeNode *T=NULL;
	CreateBiTree_ByString(T,"A(B(,D(G)),C(E(,H),F))");
	puts("中序递归遍历为:");
	LDR_Traverse(T);
	printf("\n");
	BiTreeNode *head=BiTreeThread(T);
	puts("中序遍历线索化后");
	LDR_Travese_AfterThread(head);
	BiTreeNode *pos=FindPointNode(head,‘D‘);
	printf("D的后继节点为\t%2c\n",FindNextNode(pos)->ch);
	pos=FindPointNode(head,‘C‘);
	printf("C的前驱节点为\t%2c\n",FindPreNode(pos)->ch);
	printf("\n");
	return 0;
} 
bubuko.com,布布扣

实战数据结构(12)_二叉树的线索化,布布扣,bubuko.com

实战数据结构(12)_二叉树的线索化

原文:http://blog.csdn.net/lynnbest/article/details/22324173

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!