1. 程式人生 > >(七)資料結構之搜尋二叉樹的簡單實現

(七)資料結構之搜尋二叉樹的簡單實現

1、搜尋二叉樹的簡單定義

二叉搜尋樹(BST, Binary Search Tree), 也稱二叉排序樹或者二叉查詢樹。
定義:
a、是一顆二叉樹,可以為空,也可以不為空。
b、非空左子樹的所有鍵值小於其根結點的鍵值
c、非空右子樹的所有鍵值大於其根結點的鍵值。
d、左、右子樹都是二叉搜尋樹。

2、具體實現

2.1 基本資料結構

/* 二叉樹的基本資料結構的定義 */
typedef int ElementType;
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
	ElementType Data;
	BinTree Left;
	BinTree Right;
};

2.2 插入操作

/* 二叉搜尋樹的插入演算法 */
BinTree Insert( ElementType X, BinTree BST )
{
	if( !BST )
	{
		/*若原樹為空,生成並返回一個結點的二叉搜尋樹*/
		BST = (BinTree)malloc(sizeof(struct TreeNode));
		BST->Data = X;
		BST->Left = BST->Right = NULL;
	}
	else
	{
		/*開始找要插入元素的位置*/
		if( X < BST->Data )
			BST->Left = Insert( X, BST->Left);		/*遞迴插入左子樹*/
		else if( X > BST->Data )
			BST->Right = Insert( X, BST->Right);	/*遞迴插入右子樹*/
	}
	return BST;
}

2.3 刪除操作

/* 二叉樹的刪除操作,如果該結點有左右兩個子結點,則使用右子樹的最小元素替代該點 */
BinTree Delete( ElementType X, BinTree BST )
{ 
	Position Tmp = NULL;
	if( !BST ) printf("The BST is empty!\n");
	else if( X < BST->Data )
		BST->Left = Delete( X, BST->Left); 		/* 左子樹遞迴刪除 */
	else if( X > BST->Data )
		BST->Right = Delete( X, BST->Right); 	/* 右子樹遞迴刪除 */
	else 	/*找到要刪除的結點 */
	{
		if( BST->Left && BST->Right )
		{ 
			/*被刪除結點有左右兩個子結點 */
			Tmp = FindMin( BST->Right );
			/*在右子樹中找最小的元素填充刪除結點*/
			BST->Data = Tmp->Data;
			BST->Right = Delete( BST->Data, BST->Right);	/*在刪除結點的右子樹中刪除最小元素*/
		} 
		else 
		{
			/*被刪除結點有一個或無子結點*/
			Tmp = BST;
			if( !BST->Left ) 		/* 有右孩子或無子結點*/
				BST = BST->Right;
			else if( !BST->Right ) 	/*有左孩子或無子結點*/
				BST = BST->Left;
			free( Tmp );
		}
	}
	return BST;
}

2.4 查詢指定元素

有兩種方式:遞迴和非遞迴方式。

2.4.1 遞迴方式

/* 查詢指定元素的位置 */
Position Find( ElementType X, BinTree BST )
{
	if( !BST ) return NULL; 	/*查詢失敗*/
	if( X > BST->Data )
		return Find( X, BST->Right ); /*在右子樹中繼續查詢*/
	else if( X < BST->Data )
		return Find( X, BST->Left ); /*在左子樹中繼續查詢*/
	else 
		return BST; 				 /*查詢成功,返回結點的找到結點的地址*/
}

2.4.2 非遞迴方式

/* 查詢指定元素的位置 */
Position IterFind( ElementType X, BinTree BST )
{
	while(BST)
	{
		if( X > BST->Data )
			BST = BST->Right;
		else if (X < BST->Data)
			BST = BST->Left;
		else 
			return BST;
	}
	return NULL;
}

2.5 查詢最小值

也分為兩種方式:遞迴和非遞迴。

2.5.1 遞迴方式

/* 找到這個二叉樹中的最小值的位置 */
Position FindMin( BinTree BST )
{
	if( !BST ) return NULL; /*空的二叉搜尋樹,返回NULL*/
	else if( !BST->Left )
		return BST; 		/*找到最左葉結點並返回*/
	else
		return FindMin( BST->Left ); /*沿左分支繼續查詢*/
}

2.5.2 非遞迴方式

/* 查詢最小元素所在的位置 */
Position IterFindMin( BinTree BST )
{
	if(BST )
	{
		/*沿左分支繼續查詢,直到最左葉結點*/
		while( BST->Left) BST = BST->Left;
	}
	return BST;
}

2.6 查詢最大值

也分為兩種:遞迴和非遞迴。

2.6.1 遞迴方式

/* 找到這個二叉樹中的最大值的位置 */
Position FindMax( BinTree BST )
{
	if( !BST ) return NULL; /*空的二叉搜尋樹,返回NULL*/
	else if (!BST->Right)
		return BST;
	else
		return FindMax( BST->Right); /*沿右分支繼續查詢*/
}

2.6.2 非遞迴方式

/* 查詢最大元素所在的位置 */
Position IterFindMax( BinTree BST )
{
	if(BST )
	{
		/*沿右分支繼續查詢,直到最右葉結點*/
		while( BST->Right ) BST = BST->Right;
	}
	return BST;
}

2.7 完整示例程式碼實現

/* 二叉搜尋樹的基本實現 */
#include <stdio.h>
#include <stdlib.h>

/* 二叉樹的基本資料結構的定義 */
typedef int ElementType;
typedef struct TreeNode *BinTree;
typedef BinTree Position;
struct TreeNode{
	ElementType Data;
	BinTree Left;
	BinTree Right;
};

/* 建立一顆二叉樹, 先建立根節點,然後建立左子樹,最後建立右子樹*/
BinTree CreatBinTree()  
{  
    ElementType data;  
    BinTree T;  
    scanf("%d", &data);   // 通過控制檯獲得一個結點資料  
    if(0 == data)       // 如果為空樹結點  
    {  
        T = NULL;  
    }  
    else    // 如果為非空樹結點  
    {  
        T = (BinTree)malloc(sizeof(struct TreeNode));  // 分配一塊記憶體給根結點  
        if(NULL == T) return NULL;  
        T->Data= data;    
        T->Left = CreatBinTree();      // 遞迴建立左子樹  
        T->Right = CreatBinTree();     // 遞迴建立右子樹  
    }  
    return T;   // 返回樹根結點  
}  

/* 銷燬一顆二叉樹 */
void DestroyBinTree(BinTree BT)
{
	if (BT)
	{
		DestroyBinTree(BT->Left);
		DestroyBinTree(BT->Right);
		free(BT);
		BT = NULL;
	}
}

/********************************* 遞迴操作 ******************************************/

/* 查詢指定元素的位置 */
Position Find( ElementType X, BinTree BST )
{
	if( !BST ) return NULL; 	/*查詢失敗*/
	if( X > BST->Data )
		return Find( X, BST->Right ); /*在右子樹中繼續查詢*/
	else if( X < BST->Data )
		return Find( X, BST->Left ); /*在左子樹中繼續查詢*/
	else 
		return BST; 				 /*查詢成功,返回結點的找到結點的地址*/
}

/* 找到這個二叉樹中的最小值的位置 */
Position FindMin( BinTree BST )
{
	if( !BST ) return NULL; /*空的二叉搜尋樹,返回NULL*/
	else if( !BST->Left )
		return BST; 		/*找到最左葉結點並返回*/
	else
		return FindMin( BST->Left ); /*沿左分支繼續查詢*/
}

/* 找到這個二叉樹中的最大值的位置 */
Position FindMax( BinTree BST )
{
	if( !BST ) return NULL; /*空的二叉搜尋樹,返回NULL*/
	else if (!BST->Right)
		return BST;
	else
		return FindMax( BST->Right); /*沿右分支繼續查詢*/
}

/* 二叉搜尋樹的插入演算法 */
BinTree Insert( ElementType X, BinTree BST )
{
	if( !BST )
	{
		/*若原樹為空,生成並返回一個結點的二叉搜尋樹*/
		BST = (BinTree)malloc(sizeof(struct TreeNode));
		BST->Data = X;
		BST->Left = BST->Right = NULL;
	}
	else
	{
		/*開始找要插入元素的位置*/
		if( X < BST->Data )
			BST->Left = Insert( X, BST->Left);		/*遞迴插入左子樹*/
		else if( X > BST->Data )
			BST->Right = Insert( X, BST->Right);	/*遞迴插入右子樹*/
	}
	return BST;
}

/* 二叉樹的刪除操作,如果該結點有左右兩個子結點,則使用右子樹的最小元素替代該點 */
BinTree Delete( ElementType X, BinTree BST )
{ 
	Position Tmp = NULL;
	if( !BST ) printf("The BST is empty!\n");
	else if( X < BST->Data )
		BST->Left = Delete( X, BST->Left); 		/* 左子樹遞迴刪除 */
	else if( X > BST->Data )
		BST->Right = Delete( X, BST->Right); 	/* 右子樹遞迴刪除 */
	else 	/*找到要刪除的結點 */
	{
		if( BST->Left && BST->Right )
		{ 
			/*被刪除結點有左右兩個子結點 */
			Tmp = FindMin( BST->Right );
			/*在右子樹中找最小的元素填充刪除結點*/
			BST->Data = Tmp->Data;
			BST->Right = Delete( BST->Data, BST->Right);	/*在刪除結點的右子樹中刪除最小元素*/
		} 
		else 
		{
			/*被刪除結點有一個或無子結點*/
			Tmp = BST;
			if( !BST->Left ) 		/* 有右孩子或無子結點*/
				BST = BST->Right;
			else if( !BST->Right ) 	/*有左孩子或無子結點*/
				BST = BST->Left;
			free( Tmp );
		}
	}
	return BST;
}


/* 先序遞迴遍歷 */
void PreOrderTraversal( BinTree BST )
{
	if( BST ) 
	{
		printf("%d ", BST->Data);
		PreOrderTraversal( BST->Left );
		PreOrderTraversal( BST->Right );
	}
}

/* 中序遞迴遍歷 */
void InOrderTraversal( BinTree BST )
{
	if( BST ) 
	{
		InOrderTraversal( BST->Left );
		printf("%d ", BST->Data);
		InOrderTraversal( BST->Right );
	}
}

/* 後序遞迴遍歷 */
void PostOrderTraversal( BinTree BST )
{
	if( BST )
	{
		PostOrderTraversal( BST->Left );
		PostOrderTraversal( BST->Right);
		printf("%d ", BST->Data);
	}
}


/********************************* 非遞迴操作 ****************************************/

/* 查詢指定元素的位置 */
Position IterFind( ElementType X, BinTree BST )
{
	while(BST)
	{
		if( X > BST->Data )
			BST = BST->Right;
		else if (X < BST->Data)
			BST = BST->Left;
		else 
			return BST;
	}
	return NULL;
}

/* 查詢最小元素所在的位置 */
Position IterFindMin( BinTree BST )
{
	if(BST )
	{
		/*沿左分支繼續查詢,直到最左葉結點*/
		while( BST->Left) BST = BST->Left;
	}
	return BST;
}


/* 查詢最大元素所在的位置 */
Position IterFindMax( BinTree BST )
{
	if(BST )
	{
		/*沿右分支繼續查詢,直到最右葉結點*/
		while( BST->Right ) BST = BST->Right;
	}
	return BST;
}


/* 程式入口 */
int main()
{
	ElementType input;
	BinTree node = NULL;
	BinTree tree = NULL;

	/* 建立一顆二叉樹 */
	tree = CreatBinTree();

	/* 遍歷 */
	printf("************************Traversal***************************\n");
	printf("Pre : "); PreOrderTraversal(tree); printf("\n");
	printf("In : "); InOrderTraversal(tree); printf("\n");
	printf("Post : "); PostOrderTraversal(tree); printf("\n");

	/* 遞迴查詢 */
	printf("************************Search******************************\n");
	printf("Input a number to search : ");
	scanf("%d", &input);
	node = Find(input, tree);
	printf("The search value is : %d\n", node->Data);
	node = FindMin(tree);
	printf("Min value is : %d\n", node->Data);
	node = FindMax(tree);
	printf("Max value is : %d\n", node->Data);

	/* 非遞迴查詢 */
	printf("************************IterSearch******************************\n");
	printf("Input a number to search : ");
	scanf("%d", &input);
	node = IterFind(input, tree);
	printf("The search value is : %d\n", node->Data);
	node = IterFindMin(tree);
	printf("Min value is : %d\n", node->Data);
	node = IterFindMax(tree);
	printf("Max value is : %d\n", node->Data);

	/* 插入一個元素 */
	printf("************************Insert******************************\n");
	printf("Input a number to insert : ");
	scanf("%d", &input);
	tree = Insert(input, tree);
	printf("Pre : "); PreOrderTraversal(tree); printf("\n");

	/*  刪除一個元素*/
	printf("************************Delete******************************\n");
	printf("Input a number to delete : ");
	scanf("%d", &input);
	tree = Delete(input, tree);
	printf("Pre : "); PreOrderTraversal(tree); printf("\n");

	DestroyBinTree(tree);		/* 銷燬一顆二叉樹 */
	
	return 0;
}