小螞蟻學習數據結構(21)——線索二叉樹的創建遍歷代碼實現

    今天寫了一下線索二叉樹的建立和遍歷,感受還能夠,不算很難,把思路理清楚以後,就好下手了。數據結構

    記得剛開始看數據結構的時候,感受很是頭疼,如今愈來愈感受有意思了,固然,主要是在解決了一個問題以後的成就感讓人很知足。
函數

/*
	線索二叉樹的創建,遍歷代碼實現
*/
# include <stdio.h>
# include <stdlib.h>
# include <malloc.h>

//這裏失誤了,剛開始都加了";"號,致使報錯missing ')' before ';'
# define LINK 	0
# define THREAD 1
# define OK 	1
# define ERROR	0

typedef char TElemType;
typedef int	Status;	

/*
	線索樹節點
*/
typedef struct BiThrNode
{
	TElemType data;
	struct BiThrNode * lchild, * rchild;	//左右孩子的指針
	Status LTag, RTag;
}BITHRTREE, * PBITHRTREE;

//定義一個全局變量pre,用於指定一個前驅元素
PBITHRTREE pre = NULL;

/*
	建立一顆二叉樹
	第一次定義這個函數的時候是這樣寫的
	Status CreateTree( PBITHRTREE );
	報錯:error C2668: 'CreateTree' : ambiguous call to overloaded function
	緣由是使用了引用,而在函數前置中沒有體現出來,須要改成:
	Status CreateTree( PBITHRTREE &  );
*/
Status CreateTree( PBITHRTREE &  );

/* 使用遞歸的方法,中序遍歷二叉樹 */
Status InOrderTraveler( PBITHRTREE & );

/* 爲二叉樹添加線索 */
Status InOrderTreading( PBITHRTREE &, PBITHRTREE );

/* 中序遍歷的方式添加線索 */
Status InThreading( PBITHRTREE );

/* 按照線索遍歷二叉樹 */
Status InOrderTraveler_Thread( PBITHRTREE & );

/*
	建立一個二叉樹,空格表明無子樹。
	函數的形參,使用引用的方式,操做簡便。
*/
Status CreateTree( PBITHRTREE &BaseTree )
{
	TElemType data;
	
	scanf( "%c", &data );
	
	if( ' ' == data )
	{
		BaseTree = NULL;
	}
	else
	{
		BaseTree = ( PBITHRTREE )malloc( sizeof( BITHRTREE ) );
		BaseTree -> data = data;
		CreateTree( BaseTree -> lchild );
		CreateTree( BaseTree -> rchild );
	}
	
	return OK;
}

/*
	使用遞歸的方法,中序遍歷二叉樹
	PS:其實寫這個中序遍歷的函數,主要是想看看方纔的二叉樹生成了沒
	……囧……
*/
Status InOrderTraveler( PBITHRTREE &BaseTree )
{
	if( NULL != BaseTree )
	{
		InOrderTraveler( BaseTree -> lchild );
		printf( "%c", BaseTree -> data );
		InOrderTraveler( BaseTree -> rchild );
	}
	
	return OK;
}

/*
	爲一個二叉樹添加線索,以中序爲例
	@param	PBITHRTREE	&ThreadTree 要生成的線索二叉樹
	@param	PBITHRTREE	&BaseTree	已經生成基礎二叉樹
	return Status;
*/
Status InOrderTreading( PBITHRTREE &ThreadTree, PBITHRTREE BaseTree )
{
	//建立一個頭結點
	ThreadTree = ( PBITHRTREE )malloc( sizeof( BITHRTREE ) );

	ThreadTree -> LTag = LINK;
	ThreadTree -> RTag = THREAD;
	ThreadTree -> rchild = ThreadTree;	//右指針回指
	
	if( NULL == BaseTree )
	{
		ThreadTree -> lchild = ThreadTree; //基礎樹爲空,這左孩子回指
	}
	else
	{
		ThreadTree -> lchild = BaseTree;
		// 這裏須要一個全局變量,來指示前驅元素
		pre = ThreadTree;
		
		InThreading( BaseTree );
		
		pre -> RTag = THREAD;
		pre -> rchild = ThreadTree;
		ThreadTree -> rchild = pre;
	}
	
	return OK;
}

/* 中序的方式設置線索 */
Status InThreading( PBITHRTREE Tree )
{
	if( NULL != Tree )
	{
		InThreading( Tree -> lchild );
		
		if( NULL == Tree -> lchild )
		{
			//若是右孩子是空,那麼放入前驅元素
			Tree -> LTag = THREAD;
			Tree -> lchild = pre;
		}
		
		if( NULL == pre -> rchild )
		{
			/*  
				若是這個前驅元素的右孩子爲空,就把當前節點的指針賦予它
				做爲後繼元素
			*/
			pre -> RTag = THREAD;
			pre -> rchild = Tree;
		}
		pre = Tree;
		
		InThreading( Tree -> rchild );
	}
	
	return OK;
}

/* 按照線索遍歷二叉樹 */
Status InOrderTraveler_Thread( PBITHRTREE & Tree )
{
	
	PBITHRTREE p = Tree -> lchild;
	
	while( p != Tree )
	{
		/*
			首先,一路查找每一個元素的ltag是否是等於1
			若是等於1,說明這是第一個節點,將其值輸出
			注意!!!
			怎麼會這樣呢?(其實我想說個我草),下行一開始寫的
			while( p -> LTag != LINK )
			沒法找到第一個節點,致使遍歷出錯,之後長點心吧
		*/
		while( p -> LTag != THREAD )
		{
			//printf( "遍歷到了%c,他的LTag是%d\n", p -> data, p -> LTag );
			p = p -> lchild;
		}
		
		//循環退出,說明這是第一個節點,輸出其值
		printf( "%c", p -> data );
		
		/*
			查看他的LTag,若是也是1,說明是線索,直接輸出
			若是不是1,說明他有孩子,將指針下移一位,
			從第一個while那裏按照這裏的思路再循環一次
		*/
		while( p -> RTag == THREAD && p -> rchild != Tree )
		{
			p = p -> rchild;
			printf( "%c", p -> data );
		}
		
		p = p -> rchild;
	}
	
	return OK;
}

Status main( void )
{
	PBITHRTREE ThreadTree = NULL, BaseTree = NULL;
	//首先建造一顆不帶線索的二叉樹
	printf( "請輸入一顆二叉樹:\n" );
	CreateTree( BaseTree );
	
	printf( "中序遞歸遍歷二叉樹:\n" );
	InOrderTraveler( BaseTree );
	printf( "\n" );
	
	printf( "將剛纔創造的二叉樹線索化。……  Lording ……" );
	InOrderTreading( ThreadTree, BaseTree );
	
	printf( "\n" );
	
	printf( "按照線索遍歷二叉樹:\n" );
	InOrderTraveler_Thread( ThreadTree );
	printf( "\n" );
	
	return 0;
}
/*
	VC++6.0中輸出的結果是
	=======================================
	請輸入一顆二叉樹:
	ABEQ  F   CD
	中序遞歸遍歷二叉樹:
	QEFBADC
	將剛纔創造的二叉樹線索化。……  Lording ……
	按照線索遍歷二叉樹:
	QEFBADC
	=======================================
	總結:
		須要總結的地方太多了,都是一些白癡性錯誤,邏輯上仍是比較清晰的。
		好比說:
			預約義不用就加「;」
			修改函數類型的時候,記得把前置函數定義哪裏也修改了
			還有就是須要在編寫的時候,再 認真一些。

*/


     學PHP的小螞蟻 博客 http://my.oschina.net/woshixiaomayi/blogspa

相關文章
相關標籤/搜索