二叉樹的創建及其遍歷

https://www.github.com/wangzhijun_0224/AlgorithmStudy.git

.h文件:

#ifndef _DS_CHARPTER05_H_
#define _DS_CHARPTER05_H_

/*************************************************************************************************/
// 二叉樹的結點抽象
#define BTREE_HAVE_PARENT		1

typedef struct treenode* tlink;
tlink  tlink_new_tnode(int item_size, void* pitem);	        // 獲取一個節點,並將pitem所指向的item拷貝到節點中
void   tlink_get_item(tlink p, int item_size, void *pitem);	// 獲取節點的item數據
void   tlink_insert_left(tlink p, tlink newnode);			// 將newnode插入到p的左兒子上
void   tlink_insert_right(tlink p, tlink newnode);			// 將newnode插入到p的右兒子上
void   tlink_insert_both(tlink p, tlink left, tlink right);
#if BTREE_HAVE_PARENT
tlink  tlink_get_parent(tlink p);
#endif
tlink  tlink_get_lchild(tlink p);
tlink  tlink_get_rchild(tlink p);
tlink* tlink_get_lchild_addr(tlink p);
tlink* tlink_get_rchild_addr(tlink p);

/*************************************************************************************************/
// 二叉樹抽象
typedef struct binary_tree* btree;

btree btree_open(int item_size);	// 創建一個空樹
void btree_close(btree bt);
int btree_is_empty(btree bt);		// 判斷樹是否爲空
void btree_make_btree(btree bt, void *pitem, void* penditem);
void btree_get_item(btree bt, tlink root, void *pitem);	// 獲取以root爲根結點的根節點數據
tlink btree_get_root(btree bt);
#if BTREE_HAVE_PARENT
tlink btree_get_parent(btree bt, tlink root);	// 獲取root節點的父節點
#endif
tlink btree_get_lchild(btree bt, tlink root);	// 獲取以root爲根節點的左子樹
tlink btree_get_rchild(btree bt, tlink root);	// 獲取以root爲根節點的右子樹

int btree_preorder_recursion(btree bt, void* pitem);     // 遞歸版前序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數
int btree_inorder_recursion(btree bt, void* pitem);      // 遞歸版中序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數
int btree_postorder_recursion(btree bt, void* pitem);    // 遞歸版後序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數

int btree_preorder_norecursion(btree bt, void* pitem);   // 非遞歸版前序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數
int btree_preorder_norecursion2(btree bt, void* pitem);  // 非遞歸版前序遍歷樹,另一種方法
int btree_inorder_norecursion(btree bt, void* pitem);    // 非遞歸版中序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數
int btree_postorder_norecursion(btree bt, void* pitem);  // 非遞歸版後序遍歷樹,結果存放在pitem數組中,返回值爲樹中元素個數
int btree_postorder_norecursion2(btree bt, void* pitem); // 非遞歸版後序遍歷樹,另一種方法
int btree_levelorder(btree bt, void* pitem);             // 層序遍歷樹,同層從左至右
int btree_levelorderR(btree bt, void* pitem);            // 層序遍歷樹,同層從右至左
#endif


.c文件:

#include "DS_charpter04.h"  // stack, queue

#include "DS_charpter05.h"

#include <stdlib.h>
#include <assert.h>
#include <string.h>
/*************************************************************************************************/
/***********************************************************************************
單鏈表節點抽象
***********************************************************************************/
// 不完全類型,申請節點的空間是需要加上item的大小
struct treenode{ 
#if BTREE_HAVE_PARENT
tlink parent;
#endif
tlink left, right; 
};

tlink  tlink_new_tnode(int item_size, void* pitem)
{
	tlink newnode = (tlink)malloc(sizeof(*newnode) + item_size);
	void* dst;

	if (NULL != newnode)
	{
	#if BTREE_HAVE_PARENT
		newnode->parent = NULL;
	#endif
		newnode->left = newnode->right = NULL;
		dst = (char *)newnode + sizeof(*newnode);
		memcpy(dst, pitem, item_size);
	}

	return newnode;
}

void   tlink_get_item(tlink p, int item_size, void *pitem)
{
	assert(NULL != p);
	assert(NULL != pitem);

	void *src = (char *)p + sizeof(*p);
	memcpy(pitem, src, item_size);
}

void   tlink_insert_left(tlink p, tlink newnode)
{
#if BTREE_HAVE_PARENT
	if (newnode != NULL) newnode->parent = p;
#endif
	p->left = newnode;
}

void   tlink_insert_right(tlink p, tlink newnode)
{
#if BTREE_HAVE_PARENT
	if (newnode != NULL) newnode->parent = p;
#endif
	p->right = newnode;
}

void tlink_insert_both(tlink p, tlink left, tlink right)
{
#if BTREE_HAVE_PARENT
	if (left != NULL)	left->parent = p;
	if (right != NULL)	right->parent = p;
#endif

	p->left = left;
	p->right = right;


}
#if BTREE_HAVE_PARENT
tlink  tlink_get_parent(tlink p)
{
	return p->parent;
}
#endif
tlink  tlink_get_lchild(tlink p)
{
	return p->left;
}
tlink  tlink_get_rchild(tlink p)
{
	return p->right;
}

tlink* tlink_get_lchild_addr(tlink p)
{
	return &(p->left);
}
tlink* tlink_get_rchild_addr(tlink p)
{
	return &(p->right);
}

/*************************************************************************************************/
// 二叉樹抽象
struct binary_tree
{
	tlink root;
	int item_size;
};

btree btree_open(int item_size)
{
	assert(item_size > 0);

	btree bt = (btree)malloc(sizeof(*bt));
	if (NULL == bt) return bt;

	bt->item_size = item_size;
	bt->root = NULL;

	return bt;
}

static void btree_del(tlink root)
{
	if (NULL != root)
	{
		btree_del(root->left);
		btree_del(root->right);
		free(root);
	}
}

void btree_close(btree bt)
{
	btree_del(bt->root);

	free(bt);
}

int btree_is_empty(btree bt)
{
	assert(NULL != bt);

	return (bt->root == NULL);
}

#if BTREE_HAVE_PARENT
static int btree_create_p(tlink parent, tlink *root, void* pitem, int* pindex, int item_size, void* enditem)
{
	void* pcuritem = (char*)pitem + (*pindex)*item_size;

	if (0 == memcmp(pcuritem, enditem, item_size))
	{
		return 0;
	}

	*root = tlink_new_tnode(item_size, pcuritem);
	if (NULL == *root)  return 0;

	(*root)->parent = parent;
	
	(*pindex)++;
	btree_create_p(*root, tlink_get_lchild_addr(*root), pitem, pindex, item_size, enditem);
	(*pindex)++;
	btree_create_p(*root, tlink_get_rchild_addr(*root), pitem, pindex, item_size, enditem);
	return 1;
}
#else
static int btree_create(tlink *root, void* pitem, int* pindex, int item_size, void* enditem)
{
	void* pcuritem = (char*)pitem + (*pindex)*item_size;

	if (0 == memcmp(pcuritem, enditem, item_size))
	{
		return 0;
	}

	*root = tlink_new_tnode(item_size, pcuritem);
	if (NULL == *root)  return 0;

	(*pindex)++;
	btree_create(tlink_get_lchild_addr(*root), pitem, pindex, item_size, enditem);
	(*pindex)++;
	btree_create(tlink_get_rchild_addr(*root), pitem, pindex, item_size, enditem);
	return 1;
}
#endif

void btree_make_btree(btree bt, void *pitem, void* penditem)
{
	int index = 0;
	#if BTREE_HAVE_PARENT
	btree_create_p(NULL, &(bt->root), pitem, &index, bt->item_size, penditem); // root's parent is NULL
	#else
	btree_create(&(bt->root), pitem, &index, bt->item_size, penditem);
	#endif
}

void btree_get_item(btree bt, tlink root, void *pitem)
{
	assert(bt != NULL);
	assert(root != NULL);
	assert(pitem != NULL);

	tlink_get_item(root, bt->item_size, pitem);
}
tlink btree_get_root(btree bt)
{
	return bt->root;
}

#if BTREE_HAVE_PARENT
tlink btree_get_parent(btree bt, tlink root)
{
	if (NULL == root)	return NULL;
	else	return tlink_get_parent(root);
}

#endif

tlink btree_get_lchild(btree bt, tlink root)
{
	if (NULL == root)	return NULL;
	else	return tlink_get_lchild(root);
}

tlink btree_get_rchild(btree bt, tlink root)
{
	if (NULL == root)	return NULL;
	else	return tlink_get_rchild(root);
}

/*************************************************************************************************/
/***********************************************************************************
遞歸版前序遍歷: 根節點-左孩子-右孩子的順序遍歷
***********************************************************************************/
static void preorder_recursion(btree bt, tlink root, void* pitem, int* pindex)
{
	char *dst;

	if (NULL != root)
	{
		dst = (char*)pitem + (*pindex)*sizeof(char);
		btree_get_item(bt, root, dst);
		(*pindex)++;
		preorder_recursion(bt, btree_get_lchild(bt, root), pitem, pindex);
		preorder_recursion(bt, btree_get_rchild(bt, root), pitem, pindex);
	}
}

/***********************************************************************************
遞歸版中序遍歷: 左孩子-根節點-右孩子
***********************************************************************************/
static void inorder_recursion(btree bt, tlink root, void* pitem, int* pindex)
{
	char *dst;

	if (NULL != root)
	{
		inorder_recursion(bt, btree_get_lchild(bt, root), pitem, pindex);
		dst = (char*)pitem + (*pindex)*sizeof(char);
		btree_get_item(bt, root, dst);
		(*pindex)++;
		inorder_recursion(bt, btree_get_rchild(bt, root), pitem, pindex);
	}
}

/***********************************************************************************
遞歸版後序遍歷: 左孩子-右孩子-根節點
***********************************************************************************/
static void postorder_recursion(btree bt, tlink root, void* pitem, int* pindex)
{
	char *dst;

	if (NULL != root)
	{
		postorder_recursion(bt, btree_get_lchild(bt, root), pitem, pindex);
		postorder_recursion(bt, btree_get_rchild(bt, root), pitem, pindex);
		dst = (char*)pitem + (*pindex)*sizeof(char);
		btree_get_item(bt, root, dst);
		(*pindex)++;
	}
}

int btree_preorder_recursion(btree bt, void* pitem)
{
	tlink root = NULL;
	int index = 0;
	assert(NULL != bt);
	assert(NULL != pitem);

	root = btree_get_root(bt);

	preorder_recursion(bt, root, pitem, &index);

	return index;
}

int btree_inorder_recursion(btree bt, void* pitem)
{
	tlink root = NULL;
	int index = 0;
	assert(NULL != bt);
	assert(NULL != pitem);

	root = btree_get_root(bt);

	inorder_recursion(bt, root, pitem, &index);

	return index;
}

int btree_postorder_recursion(btree bt, void* pitem)
{
	tlink root = NULL;
	int index = 0;
	assert(NULL != bt);
	assert(NULL != pitem);

	root = btree_get_root(bt);

	postorder_recursion(bt, root, pitem, &index);

	return index;
}

/*************************************************************************************************/
#if (!BTREE_HAVE_PARENT)

/***********************************************************************************
非遞歸版前序遍歷:
根據前序遍歷訪問的順序,優先訪問根節點,然後再分別訪問左孩子和右孩子,即對於任一節點,其可看做是根節點,
因此可直接訪問,訪問完之後,若其左孩子不爲空,按相同規則訪問它的左子樹;當訪問完其左子樹時,再訪問它的右子樹。

對於任一結點P:
1)訪問結點P,並將結點P入棧;
2)判斷結點P的左孩子是否爲空,若爲空,則從棧中取出棧頂元素,並將棧頂結點的右孩子置爲當前的結點P,循環至1);
若不爲空,則將P的左孩子置爲當前的結點P;
3)直到棧爲空,則遍歷結束。
***********************************************************************************/
int btree_preorder_norecursion(btree bt, void* pitem)
{
	tlink root = btree_get_root(bt);
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);
	
	stack_slist stk = stack_slist_open(sizeof(root));

	while (1)
	{
		while (NULL != root)
		{
			dst = (char*)pitem + index*sizeof(char);
			btree_get_item(bt, root, dst);
			index++;
			
			stack_slist_insert(stk, &root);
			
			root = btree_get_lchild(bt, root);
		}
		
		if (0 == stack_slist_del(stk, &root)) break;    // 棧爲空 
		
		root = btree_get_rchild(bt, root);
	}
	
	stack_slist_close(stk);
	
	return index;
}

#else
/***********************************************************************************
帶有parent屬性的前序非遞歸遍歷:
對於任一結點root:
1)訪問結點root;
2)判斷root的左孩子是否爲空,若不爲空,則將root的左孩子設置爲root,循環至1);若爲空,則轉至3);
3)取root的右孩子,如果root的右孩子不爲空,則將root的右孩子設置爲root,循環至1);
  若爲空,則沿root的parent往上搜索,直到parent爲空(則遍歷結束)或找到一個parent的右孩子不爲root爲止,
  將此parent的右孩子設置爲root,循環至1)
***********************************************************************************/
int btree_preorder_norecursion(btree bt, void* pitem)
{
	tlink root, left, right, parent;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	for (root = btree_get_root(bt); root != NULL; )
	{
        while (1)
		{
			dst = (char*)pitem + index*sizeof(char);
			btree_get_item(bt, root, dst);
			index++;

			left = btree_get_lchild(bt, root);
			if (NULL == left)	break;
			else	root = left;
		}

		right = btree_get_rchild(bt, root);
		if (NULL == right)	// 右子樹遍歷完成
		{
			// 沿二叉樹往上搜索,直到parent爲空或找到一個parent的右節點不爲root爲止
			parent = tlink_get_parent(root);
			while (NULL != parent && root == btree_get_rchild(bt, parent))
			{
				root = parent;
				parent = tlink_get_parent(parent);
			}
			
			if (NULL != parent) root = btree_get_rchild(bt, parent);
			else break;
				
		}
		else	// 有右子樹,遍歷右子樹
		{
			root = right;
		}
	}
	
	return index;
}
#endif

/***********************************************************************************
非遞歸版前序遍歷2:
***********************************************************************************/
int btree_preorder_norecursion2(btree bt, void* pitem)
{
	tlink root = btree_get_root(bt), tmplink;
	stack_slist stk;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	if (NULL == root)   return 0; // 空節點不入棧

	stk = stack_slist_open(sizeof(root));

	stack_slist_insert(stk, &root);

	while (1)
	{
		if (0 == stack_slist_top(stk, &root))    break;

		dst = (char*)pitem + index*sizeof(char);
		btree_get_item(bt, root, dst);
		index++;

		stack_slist_pop(stk);

		tmplink = btree_get_rchild(bt, root);
		if (NULL != tmplink) stack_slist_insert(stk, &tmplink);

		tmplink = btree_get_lchild(bt, root);
		if (NULL != tmplink) stack_slist_insert(stk, &tmplink);
	}

	stack_slist_close(stk);

	return index;
}

#if (!BTREE_HAVE_PARENT)

/***********************************************************************************
非遞歸版中序遍歷:
根據中序遍歷的順序,對於任一節點,優先訪問其左孩子,而左孩子節點又可看做根節點,
然後繼續訪問其左孩子節點,直到遇到左孩子爲空的節點才進行訪問,然後按相同的規則訪問其右子樹。

對於任一結點P:
1)若結點P的左孩子不爲空,則將P入棧並將P的左孩子置爲當前的P,然後循環當前判斷;
若P的左孩子爲空,則從棧中取出棧頂元素,訪問棧頂節點,然後將當前的P設爲棧頂節點的右孩子;
3)直到棧爲空,則遍歷結束。
***********************************************************************************/
int btree_inorder_norecursion(btree bt, void* pitem)
{
	tlink tmplink;
	stack_slist stk;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	tmplink = btree_get_root(bt);
	stk = stack_slist_open(sizeof(tmplink));

	while (1)
	{
		while (tmplink != NULL)
		{
			stack_slist_insert(stk, &tmplink);
			tmplink = btree_get_lchild(bt, tmplink);
		}

		if (0 == stack_slist_del(stk, &tmplink)) break;

		dst = (char*)pitem + index*sizeof(char);
		index++;
		btree_get_item(bt, tmplink, dst);

		tmplink = btree_get_rchild(bt, tmplink);
	}

	stack_slist_close(stk);

	return index;
}
#else
/***********************************************************************************
帶有parent屬性的中序非遞歸遍歷:
對於任一結點root:
1)判斷root的左孩子是否爲空,若不爲空,則將root的左孩子設置爲root,循環本步驟;
  若爲空,則轉至2);
2)訪問節點root,然後判斷root的右孩子是否爲空,若不爲空,則將root的右孩子設置爲root,循環至1);
  若爲空,則沿root的parent往上搜索,直到parent爲空(則遍歷結束)或找到一個parent的右孩子不爲root爲止,
  此時先訪問parent的值,再將此parent的右孩子設置爲root,循環至1)
***********************************************************************************/
int btree_inorder_norecursion(btree bt, void* pitem)
{
	tlink root, parent, left, right;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	root = btree_get_root(bt);

	while (NULL != root)
	{
		while(1)
		{
			left = btree_get_lchild(bt, root);
			if (NULL == left)	break;	// 左子樹遍歷完成
			else root = left;
		}

		dst = (char*)pitem + index*sizeof(char);
		index++;
		btree_get_item(bt, root, dst);
			
		right = btree_get_rchild(bt, root);
		if (NULL == right)	
		{
			parent = tlink_get_parent(root);
			while (NULL != parent && root == btree_get_rchild(bt, parent))
			{
				root = parent;
				parent = tlink_get_parent(parent);
			}
			
			if (NULL != parent) 
			{	
				// 遍歷p的右子樹之前,先訪問p
				dst = (char*)pitem + index*sizeof(char);
				index++;
				btree_get_item(bt, parent, dst);
		
				root = btree_get_rchild(bt, parent);
			}
			else break;
				
		}
		else
		{	
			root = right;
		}
	}

	return index;
}
#endif

#if (!BTREE_HAVE_PARENT)
/***********************************************************************************
非遞歸版後序遍歷1:
思路: 對於任一節點P,將其入棧,然後沿其左子樹一直往下搜索,直到搜到到美歐左孩子的節點,
此時該節點出現在棧頂,但此時不能將其出棧並訪問,因其右孩子還未被訪問。所以,接下來
按相同的規則對其右子樹進行處理,當訪問完其右孩子時,該節點又出現在棧頂,此時
可以將其出棧並訪問。
即:每個節點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。因此,多設置
一個變量標識該節點是否第一次出現在棧頂。
***********************************************************************************/
typedef struct pstorder_stack_item
{
	tlink link;
	int   flag; // 1: 第一次出現在棧頂 0:不是第一次出現在棧頂
}pstorder_stack_item;

int btree_postorder_norecursion(btree bt, void* pitem)
{
	tlink root = btree_get_root(bt);
	pstorder_stack_item stk_item;
	stack_slist stk;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	stk = stack_slist_open(sizeof(stk_item));

	while (1)
	{
		while (root != NULL)
		{
			stk_item.flag = 1;
			stk_item.link = root;
			stack_slist_insert(stk, &stk_item);
			root = btree_get_lchild(bt, root);
		}

		if (0 == stack_slist_del(stk, &stk_item)) break;

		if (1 == stk_item.flag) // 第一次在棧頂
		{
			stk_item.flag = 0;
			stack_slist_insert(stk, &stk_item);
			root = btree_get_rchild(bt, stk_item.link); // 處理右子樹
		}
		else   // 第二次在棧頂
		{
			dst = (char*)pitem + index*sizeof(char);
			btree_get_item(bt, stk_item.link, dst);
			index++;
			root = NULL;
		}
	}

	stack_slist_close(stk);

	return index;
}
#else
/***********************************************************************************
帶有parent屬性的後序非遞歸遍歷:
對於任一結點root:
1)判斷root的左孩子是否爲空,若不爲空,則將root的左孩子設置爲root,循環本步驟;
  若爲空,則轉至2);
2)然後判斷root的右孩子是否爲空,若不爲空,則將root的右孩子設置爲root,循環至1);
  若爲空,先訪問root的值,再沿root的parent往上搜索:
    若root爲parent的右節點,則訪問parent節點並繼續向上搜索;
  若搜索完成後,parent爲空,則遍歷結束;否則,將root設置爲parent的右節點,循環至1);
***********************************************************************************/
int btree_postorder_norecursion(btree bt, void* pitem)
{
	tlink root, parent, left, right;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	root = btree_get_root(bt);

	while (NULL != root)
	{
		while(1)
		{
			left = btree_get_lchild(bt, root);
			if (NULL == left)	break;	// 左子樹遍歷完成
			else root = left;
		}
			
		right = btree_get_rchild(bt, root);
		if (NULL == right)	
		{
			dst = (char*)pitem + index*sizeof(char);
			index++;
			btree_get_item(bt, root, dst);

			parent = tlink_get_parent(root);
			while (NULL != parent && root == btree_get_rchild(bt, parent))
			{
				dst = (char*)pitem + index*sizeof(char);
				index++;
				btree_get_item(bt, parent, dst);
			
				root = parent;
				parent = tlink_get_parent(parent);
			}
			
			if (NULL != parent) 
			{	
				root = btree_get_rchild(bt, parent);
			}
			else break;
				
		}
		else
		{	
			root = right;
		}
	}

	return index;
}

#endif

/***********************************************************************************
非遞歸版後序遍歷2:
思路:要保證根節點在左孩子和右孩子訪問之後才能訪問,因此對於任一節點P,先將其入棧。
如果P不存在左孩子和右孩子,則可以直接訪問它;或者P存在左孩子或者右孩子,但是其
左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該節點。若非上述兩種情況,則將P
的右孩子和左孩子依次入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面
被訪問,左孩子和右孩子都在根節點前面被訪問。
***********************************************************************************/
int btree_postorder_norecursion2(btree bt, void* pitem)
{
	tlink root = btree_get_root(bt), tmplink;
	tlink pre = NULL;
	stack_slist stk;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	if (NULL == root)   return 0;

	stk = stack_slist_open(sizeof(root));


	stack_slist_insert(stk, &root);

	while (1)
	{
		if (0 == stack_slist_top(stk, &root))    break;

		if ((NULL == btree_get_lchild(bt, root) && NULL == btree_get_rchild(bt, root))
			|| (NULL != pre && (pre == btree_get_lchild(bt, root) || pre == btree_get_rchild(bt, root)))
			)
		{
			dst = (char*)pitem + index*sizeof(char);
			btree_get_item(bt, root, dst);
			index++;

			stack_slist_pop(stk);
			pre = root;
		}
		else
		{
			tmplink = btree_get_rchild(bt, root);
			if (NULL != tmplink) stack_slist_insert(stk, &tmplink);

			tmplink = btree_get_lchild(bt, root);
			if (NULL != tmplink) stack_slist_insert(stk, &tmplink);
		}
	}

	stack_slist_close(stk);

	return index;
}


/***********************************************************************************
層序遍歷二叉樹:
一層一層從左向右遍歷
***********************************************************************************/
int btree_levelorder(btree bt, void* pitem)
{
	queue_slist qe;
	tlink root = btree_get_root(bt), tmplink;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	if (NULL == root)   return 0;

	qe = queue_slist_open(sizeof(root));

	queue_slist_insert(qe, &root);

	while (1)
	{
		if (0 == queue_slist_del(qe, &root))    break;

		dst = (char*)pitem + index*sizeof(char);
		btree_get_item(bt, root, dst);
		index++;

		tmplink = btree_get_lchild(bt, root);
		if (NULL != tmplink) queue_slist_insert(qe, &tmplink);

		tmplink = btree_get_rchild(bt, root);
		if (NULL != tmplink) queue_slist_insert(qe, &tmplink);
	}

	queue_slist_close(qe);

	return index;
}


/***********************************************************************************
層序遍歷二叉樹:
一層一層從右向左遍歷
***********************************************************************************/
int btree_levelorderR(btree bt, void* pitem)
{
	queue_slist qe;
	tlink root = btree_get_root(bt), tmplink;
	char* dst;
	int index = 0;

	assert(NULL != bt);
	assert(NULL != pitem);

	if (NULL == root)   return 0;

	qe = queue_slist_open(sizeof(root));

	queue_slist_insert(qe, &root);

	while (1)
	{
		if (0 == queue_slist_del(qe, &root))    break;

		dst = (char*)pitem + index*sizeof(char);
		btree_get_item(bt, root, dst);
		index++;

		tmplink = btree_get_rchild(bt, root);
		if (NULL != tmplink) queue_slist_insert(qe, &tmplink);

		tmplink = btree_get_lchild(bt, root);
		if (NULL != tmplink) queue_slist_insert(qe, &tmplink);
	}

	queue_slist_close(qe);

	return index;
}


test.c:

#include "DS_charpter05_test.h"

#include "DS_charpter05.h"


static void create_btree_test(void)
{
/*
樹:
	    A
	  /   \
	 B      C
	/ \    / \
     D   E  F   G
    / \
   H   I
*/
	char str[] = { 'A', 'B', 'D', 'H', '\0', '\0', 'I', '\0', '\0', 'E',
		'\0', '\0', 'C', 'F', '\0', '\0', 'G', '\0', '\0' };

	char end_item = '\0';

	btree bt = btree_open(sizeof(char));
	btree_make_btree(bt, str, &end_item);

	tlink root = btree_get_root(bt);

	char ch;
	btree_get_item(bt, root, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[0], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(NULL, btree_get_parent(bt, root));
	#endif
	
	tlink left, right;
	left = btree_get_lchild(bt, root);
	btree_get_item(bt, left, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[1], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, left));
	#endif
	
	right = btree_get_rchild(bt, root);
	btree_get_item(bt, right, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[12], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, right));
	#endif
	
	root = right;
	tlink tmp = btree_get_lchild(bt, root);
	btree_get_item(bt, tmp, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[13], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, tmp));
	#endif
	
	tmp = btree_get_rchild(bt, root);
	btree_get_item(bt, tmp, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[16], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, tmp));
	#endif
	
	root = left;
	left = btree_get_lchild(bt, root);
	btree_get_item(bt, left, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[2], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, left));
	#endif
	
	right = btree_get_rchild(bt, root);
	btree_get_item(bt, right, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[9], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, right));
	#endif
	
	root = left;
	left = btree_get_lchild(bt, root);
	btree_get_item(bt, left, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[3], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, left));
	#endif
	
	right = btree_get_rchild(bt, root);
	btree_get_item(bt, right, &ch);
	CU_ASSERT_PTR_DATA_EQUAL(&ch, &str[6], sizeof(ch));
	#if BTREE_HAVE_PARENT
	CU_ASSERT_EQUAL(root, btree_get_parent(bt, right));
	#endif
	
	btree_close(bt);
}

/*
遞歸版遍歷函數測試
*/
static void btree_order_test1(void)
{
/*
樹:
	   +
	  / \
	 *   E
	/ \
     *   D
    / \
   /    C
  / \
A   B
*/
	char str[] = { '+', '*', '*', '/', 'A', '\0', '\0', 'B', '\0', '\0',
		'C', '\0', '\0', 'D', '\0', '\0', 'E', '\0', '\0' };
	char end_item = '\0';

	char str_rlt[sizeof(str) / sizeof(str[0])];

	btree bt = btree_open(sizeof(char));
	btree_make_btree(bt, str, &end_item);

	int index = 0;

	index = btree_preorder_recursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("+**/ABCDE", str_rlt, strlen("+**/ABCDE"));

	index = btree_inorder_recursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("A/B*C*D+E", str_rlt, strlen("A/B*C*D+E"));

	index = btree_postorder_recursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("AB/C*D*E+", str_rlt, strlen("AB/C*D*E+"));

	btree_close(bt);
}

/*
非遞歸版遍歷函數測試
*/
static void btree_order_test2(void)
{
	/*
	樹:
	+
	/ \
	*   E
	/ \
	*   D
	/ \
	/    C
	/ \
	A   B
	*/
	char str[] = { '+', '*', '*', '/', 'A', '\0', '\0', 'B', '\0', '\0',
		'C', '\0', '\0', 'D', '\0', '\0', 'E', '\0', '\0' };
	char end_item = '\0';

	char str_rlt[sizeof(str) / sizeof(str[0])];


	btree bt = btree_open(sizeof(char));
	btree_make_btree(bt, str, &end_item);

	int index = 0;

	index = btree_preorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("+**/ABCDE", str_rlt, strlen("+**/ABCDE"));

	index = btree_preorder_norecursion2(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("+**/ABCDE", str_rlt, strlen("+**/ABCDE"));

	index = btree_inorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("A/B*C*D+E", str_rlt, strlen("A/B*C*D+E"));

	index = btree_postorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("AB/C*D*E+", str_rlt, strlen("AB/C*D*E+"));

	index = btree_postorder_norecursion2(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("AB/C*D*E+", str_rlt, strlen("AB/C*D*E+"));

	index = btree_levelorder(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("+*E*D/CAB", str_rlt, strlen("+*E*D/CAB"));

	index = btree_levelorderR(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("+E*D*C/BA", str_rlt, strlen("+E*D*C/BA"));

	btree_close(bt);
}

/*
非遞歸版遍歷函數測試
*/
static void btree_order_test3(void)
{
	/*
	樹:
	A
	/   \
	B      C
	/ \    / \
	D   E  F   G
	/ \
	H   I
	*/
	char str[] = { 'A', 'B', 'D', 'H', '\0', '\0', 'I', '\0', '\0', 'E',
		'\0', '\0', 'C', 'F', '\0', '\0', 'G', '\0', '\0' };

	char str_rlt[sizeof(str) / sizeof(str[0])];

	char end_item = '\0';

	btree bt = btree_open(sizeof(char));
	btree_make_btree(bt, str, &end_item);

	int index = 0;

	index = btree_preorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("ABDHIECFG", str_rlt, strlen("ABDHIECFG"));

	index = btree_preorder_norecursion2(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("ABDHIECFG", str_rlt, strlen("ABDHIECFG"));

	index = btree_inorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("HDIBEAFCG", str_rlt, strlen("HDIBEAFCG"));

	index = btree_postorder_norecursion(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("HIDEBFGCA", str_rlt, strlen("HIDEBFGCA"));

	index = btree_postorder_norecursion2(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("HIDEBFGCA", str_rlt, strlen("HIDEBFGCA"));

	index = btree_levelorder(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("ABCDEFGHI", str_rlt, strlen("ABCDEFGHI"));

	index = btree_levelorderR(bt, str_rlt);
	CU_ASSERT_EQUAL(index, 9);
	CU_ASSERT_PTR_DATA_EQUAL("ACBGFEDIH", str_rlt, strlen("ACBGFEDIH"));

	btree_close(bt);
}


/***********************************************************************************
***********************************************************************************/
CU_TestInfo tests_datasture_charpter05[] = {
	{ "create_btree_test", create_btree_test },
	{ "btree_order_test1", btree_order_test1 },
	{ "btree_order_test2", btree_order_test2 },
	{ "btree_order_test3", btree_order_test3 },
	CU_TEST_INFO_NULL,
};




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章