数据结构 第四章 树——线索二叉树(C语言)

二叉树的线索化:
如果当前结点没有左孩子,则让它的Left指针指向它的前驱结点,如果没有右孩子,则让它的Right指针指向它的后继结点,然后增设两个标志域来判断当前的指针域指向的是孩子结点还是前驱后继结点。

指向前驱结点或后继结点的指针叫做线索。

通过中序遍历线索化二叉树:

typedef struct ThreadNode{
	ElementType data;
	struct ThreadNode *Left, *Right;
	int ltag, rtag;
};

typedef struct ThreadNode* TT;

void CreatInThread( TT ptrt )
{
	TT pre = NULL;
	if( ptrt ){
		InThread( ptrt, pre );          //线索化二叉树 
		pre -> Right = NULL;            //设置最后一个结点的右指针域 
		pre -> rtag = 1;
	}
}

void InThread( TT ptrt, TT pre )
{
	if( ptrt != NULL ){
		InThread( ptrt -> Left, pre );        //递归线索化左子树 
		if( ptrt -> Left == NULL ){           //左子树为空(没有左孩子) 
			ptrt -> Left = pre;               //左子树为空就把左指针指向前驱 
			ptrt -> ltag = 1;                 //设置标志域为1 
		}
		if( pre != NULL && pre -> Right == NULL ){    //前驱结点存在且前驱的右孩子为空(没有右孩子) 
			pre -> Right = ptrt;                      //把前驱的右指针域设置为当前结点
			pre -> rtag = 1;                          //设置标志域为1 
		}
		pre = ptrt;                                   //把当前节点设置为pre,也就代表当前结点操作完成,为设置下一个结点做准备工作 
		InThread( ptrt -> Right, pre );               //递归线索化右子树   
	}
}

也可以为线索二叉树创建一个头结点,让头结点的左指针域指向根结点,右指针域指向中序遍历访问的最后一个结点,同时也让中序遍历的第一个结点的左指针域和最后一个结点的右指针域指向头结点。
修改上面代码如下:

void CreatInThread( TT ptrt )
{
	TT head = ( TT )malloc( sizeof( struct ThreadNode ) );
	head -> Left = ptrt;                //设置头结点的左指针域指向根结点 
	TT pre = NULL;
	if( ptrt ){
		InThread( ptrt, pre );          //线索化二叉树
		head -> Right = pre;            //设置头结点的右指针域指向最后一个结点 
		pre -> Right = head;            //设置最后一个结点的右指针域 
		pre -> rtag = 1;
	}
}

void InThread( TT ptrt, TT pre, TT head )
{
	if( ptrt != NULL ){
		InThread( ptrt -> Left, pre );        //递归线索化左子树 
		if( ptrt -> Left == NULL ){           //左子树为空(没有左孩子) 
			if( pre == NULL )                 //前驱为空的时候即为第一个结点 
				ptrt -> Left = head;          //设置第一个结点的左指针域指向头结点 
			else
				ptrt -> Left = pre;           //左子树为空就把左指针指向前驱 
			ptrt -> ltag = 1;                 //设置标志域为1 
		}
		if( pre != NULL && pre -> Right == NULL ){    //前驱结点存在且前驱的右孩子为空(没有右孩子) 
			pre -> Right = ptrt;                      //把前驱的右指针域设置为当前结点
			pre -> rtag = 1;                          //设置标志域为1 
		}
		pre = ptrt;                                   //把当前节点设置为pre,也就代表当前结点操作完成,为设置下一个结点做准备工作 
		InThread( ptrt -> Right, pre );               //递归线索化右子树   
	}
}

线索二叉树的遍历(无头结点):
(1)求中序线索二叉树中中序序列下的第一个结点:

TT FirstNode( TT ptrt )
{
	while( ptrt -> ltag != 0 )
		ptrt = ptrt -> Left;
	return ptrt; 
} 

(2)求中序线索二叉树中结点p在中序序列下的后继结点:

TT NextNode( TT ptrt )                 //找后继结点 
{
	if( ptrt -> rtag == 0 )
		return FirstNode( ptrt -> Right );
	else
		return ptrt -> Right;
}

(3)求中序线索二叉树中中序序列下的最后一个结点:

TT LastNode( TT ptrt )                 //找最后一个结点 
{
	while( ptrt -> rtag != 0 )
		ptrt = ptrt -> Right;
	return ptrt; 
} 

(4)求中序线索二叉树中结点p在中序序列下的前驱结点:

TT PreNode( TT ptrt )                 //找前驱结点 
{
	if( ptrt -> ltag == 0 )
		return LastNode( ptrt -> Left );
	else
		return ptrt -> Left;
}

(5)中序线索二叉树的中序遍历:

void InOrder( TT ptrt )               //中序线索二叉树的中序遍历 
{
	for( TT *p = FirstNode( ptrt ); p != NULL; p = NextNode( p ) )
		visit( p ); 
}

猜你喜欢

转载自blog.csdn.net/qq_40344308/article/details/89092323