二叉樹先根(先序)遍歷的改進

二叉樹的特點:每個結點的度最大不能超過2,並且左右子樹不能顛倒

二叉樹的存儲結構:下面採用鏈式存儲進行闡述,堆排序算法(快速排序改進)採用的順序存儲結構的二叉樹,先看如下結構體的存儲方式

順序存儲:

/*二叉樹的順序存儲*/
#define		MAX_TREE_SIZE	100
typedef		TElemType		SqBiTree[MAX_TREE_SIZE];


鏈式存儲:

/*二叉樹的鏈式存儲*/
typedef struct BiTNode
{
	TElemType	data;
	BiTNode		*lchild,*rchild;
}BiTNode, *BiTree;


這裏的TElemType的類型如下,這裏我使用了int型的定義:

#define INT_TYPE
#ifdef INT_TYPE
typedef int TElemType;
#elif defined FLOAT_TYPE
typedef float TElemType
#elif defined STRING_TYPE
typedef char  *TElemType
#endif
二叉樹的創建:這裏需要進行遞歸創建,如下

int CreateBiTree(BiTree &T)
{
	int nData;

	printf("Please Enter BiTree Node data:\n");	
	scanf_s("%d", &nData);

	if (nData == 0)
	{
		T = NULL;
		return OK;
	}
	else if (nData > 0 && nData < 100)
	{
		T = (BiTNode*)malloc(sizeof(BiTNode));
		if (!T)
		{
			return BTOVERFLOW;
		}
		T->data = nData;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
		return OK;
	}
#ifdef _DEBUG
	printf("Enter data Error!\n");
#endif // _DEBUG
	
	return ERROR;
}
這裏我對數據進行了限制,便於進行測試,這裏只接受0~100的數據,如果是0表明當前沒有孩子的節點(左孩子或者右孩子),如果存在就創建節點,填充數據

遍歷二叉樹:創建後之後,我必須測試創建的二叉樹中的數據是否正確,這裏採用的是先根遍歷,如下

/*遍歷二叉樹*/
int PreOrderTraverse(BiTree T, int (*VisitNode)(TElemType))
{
	if (T)
	{
		if (VisitNode(T->data))
		{
			if (PreOrderTraverse(T->lchild, VisitNode))
			{
				if (PreOrderTraverse(T->rchild, VisitNode))
				{
					return OK;
				}
			}
		}
		return ERROR;
	}
	return OK;	//如果沒有子孩子,這時候應該回溯,要查看右孩子必須爲真
}
這裏遍歷的時候採用了一個函數,注意傳遞的形參是函數指針,只是進行簡單的結點數據的輸出,如下:

int VisitNode(TElemType data)
{
#if defined(INT_TYPE) || defined(FLOAT_TYPE)
	printf("%d ", data);
#elif defined(STRING_TYPE)
	printf("%s ", data);
#endif
	return OK;
}
但是在遍歷的時候,爲什麼T爲NULL的時候,返回還是OK(1)呢,這裏主要是上面的遍歷函數的原因,因爲這裏必須是先遍歷左孩子且返回值爲真,才能遍歷右孩子,所以不能返回ERROR(0),感覺返回值有點怪,修改如下

int PreOrderTraverseEx(BiTree T, int (*VisitNode)(TElemType))
{
	if (T)
	{
		if (VisitNode(T->data))
		{
			PreOrderTraverse(T->lchild, VisitNode);
			PreOrderTraverse(T->rchild, VisitNode);
			return OK;
		}
	}
	return ERROR;	//如果沒有子孩子,這時候應該回溯
}
這樣看着就舒服多了,其實可以不使用任何返回值,主要遍歷完左右子樹不用做其他任何事情,如果還有其他,就不能沒有返回值,這裏return OK其實要不要也無所謂,因爲我根本沒有進行判斷

測試用例:如下

	BiTree T;
	if (CreateBiTree(T))
	{
		PreOrderTraverseEx(T, VisitNode);
		printf("\n");
	}
這裏對測試的數據輸入其實有一定的要求,假設根爲12 孩子結點爲 34 78,這裏應該這樣輸入數據 12 34 0 0 78 0 0,只有這樣才能正常退出,如下測試結果:

Please Enter BiTree Node data:
12
Please Enter BiTree Node data:
34
Please Enter BiTree Node data:
0
Please Enter BiTree Node data:
0
Please Enter BiTree Node data:
78
Please Enter BiTree Node data:
0
Please Enter BiTree Node data:
0
12 34 78

從前面我可以看到這裏採用的其實都是遞歸算法,我們都知道遞歸最大之弊病就是在每次下潛下一層的時候,一定要保存當前所在層次的數據,具體哪些數據其實是由操作系統OS來進行管理的,但是像每次的形參T一定會入棧,便於在層次退出返回上一層的時候使用,所以這裏就可以採用非遞歸的方式的來進行修改算法:如何做呢?請參考二叉樹先序遍歷的非遞歸算法

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