6-12 二叉搜索樹的操作集 (30 分)

#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
	ElementType Data;
	BinTree Left;
	BinTree Right;
};

void PreorderTraversal(BinTree BT); /* 先序遍歷,由裁判實現,細節不表 */
void InorderTraversal(BinTree BT);  /* 中序遍歷,由裁判實現,細節不表 */

BinTree Insert(BinTree BST, ElementType X);
BinTree Delete(BinTree BST, ElementType X);
Position Find(BinTree BST, ElementType X);
Position FindMin(BinTree BST);
Position FindMax(BinTree BST);

int main()
{
	BinTree BST, MinP, MaxP, Tmp;
	ElementType X;
	int N, i;

	BST = NULL;
	scanf("%d", &N);
	for (i = 0; i<N; i++) {
		scanf("%d", &X);
		BST = Insert(BST, X);
	}
	printf("Preorder:"); PreorderTraversal(BST); printf("\n");
	MinP = FindMin(BST);
	MaxP = FindMax(BST);
	scanf("%d", &N);
	for (i = 0; i<N; i++) {
		scanf("%d", &X);
		Tmp = Find(BST, X);
		if (Tmp == NULL) printf("%d is not found\n", X);
		else {
			printf("%d is found\n", Tmp->Data);
			if (Tmp == MinP) printf("%d is the smallest key\n", Tmp->Data);
			if (Tmp == MaxP) printf("%d is the largest key\n", Tmp->Data);
		}
	}
	scanf("%d", &N);
	for (i = 0; i<N; i++) {
		scanf("%d", &X);
		BST = Delete(BST, X);
	}
	printf("Inorder:"); InorderTraversal(BST); printf("\n");

	system("PAUSE");
	return 0;
}
/* 你的代碼將被嵌在這裏 */
//先序遍歷
void PreorderTraversal(BinTree BT){
	if (!BT)return;
	printf(" %d", BT->Data);
	PreorderTraversal(BT->Left);
	PreorderTraversal(BT->Right);
	return;
}
//中序遍歷
void InorderTraversal(BinTree BT){
	if (!BT)return;
	InorderTraversal(BT->Left);
	printf(" %d", BT->Data);
	InorderTraversal(BT->Right);
	return;
}
//遞歸插入
BinTree Insert(BinTree BST, ElementType X){
	//如果是一個空節點
	if (!BST){
		BST = (BinTree)malloc(sizeof(struct TNode));//既然爲空所以要生成一個
		BST->Data = X;
		BST->Left = NULL;
		BST->Right = NULL;
	}
	else{//一般情況
		if (X < BST->Data){//插入值小於節點,應該往左子樹中找位置
			BST->Left = Insert(BST->Left, X);//遞歸插入左子樹
		}
		else if (X > BST->Data){//插入值大於節點,應該往右子樹中找
			BST->Right = Insert(BST->Right, X);//遞歸插入右子樹
		}
		//如果相等說明X已經存在,什麼也不做
	}
	return BST;
}
//遞歸刪除
BinTree Delete(BinTree BST, ElementType X){
	Position temp;
	if (!BST){//邊界條件
		printf("Not Found\n");//如果最終樹爲空,說明沒有
	}
	else{//這裏類似於插入重點在於找到後怎麼辦
		if (X < BST->Data){
			BST->Left = Delete(BST->Left, X);//從左子樹遞歸刪除,掛接到父親的左孩子上
		}
		else if (X > BST->Data){
			BST->Right = Delete(BST->Right, X);//從右子樹遞歸刪除,掛接到父親的右孩子上
		}
		else{//當前BST就是要刪除的節點(找到的邊界)
		
			/*兩種情況:有兩個子節點,有一個子節點*/
			//有兩個子節點用臨點(左子樹最大的/右子樹最小的,用findmax,findmin進入左右子樹尋找)代替,刪除臨點
			
			if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從右子樹中找最小的數填充刪除的節點
				temp = FindMin(BST->Right);//找最小
				BST->Data = temp->Data;//填充刪除的節點
				BST->Right = Delete(BST->Right, temp->Data);//刪除拿來填充的那個節點,掛接到父親的左孩子上
			}
			/*if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從左子樹中找最大的數填充刪除的節點
				temp = FindMax(BST->Left);//找最大
				BST->Data = temp->Data;//填充刪除的節點
				BST->Left = Delete(BST->Left, temp->Data);//刪除拿來填充的那個節點,掛接到父親的右孩子上*/
			else{//只有一個子節點:重接
				temp = BST;
				if (!BST->Left){//只有右節點
					BST = BST->Right;//直接賦值就可以
				}
				else if (!BST->Right){//只有左節點
					BST = BST->Left;//直接賦值就可以
				}
				free(temp);//如果啥也沒有直接刪除就可以,當然上面兩種情況賦值後也要刪除
			}
		}
	}
	return BST;
}
Position Find(BinTree BST, ElementType X){
	while (BST){
		if (BST->Data == X)break;
		else if (X > BST->Data)BST = BST->Right;
		else BST = BST->Left;
	}
	return BST;
}
Position FindMin(BinTree BST){
	if (!BST)return BST;
	while (BST->Left){
		BST = BST->Left;
	}
	return BST;
}
Position FindMax(BinTree BST){
	if (!BST)return BST;
	while (BST->Right){
		BST = BST->Right;
	}
	return BST;
}

0.結構體

typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode{
	ElementType Data;
	BinTree Left;
	BinTree Right;
};

1.先序和中序遍歷

//先序遍歷
void PreorderTraversal(BinTree BT){
	if (!BT)return;
	printf(" %d", BT->Data);
	PreorderTraversal(BT->Left);
	PreorderTraversal(BT->Right);
	return;
}
//中序遍歷
void InorderTraversal(BinTree BT){
	if (!BT)return;
	InorderTraversal(BT->Left);
	printf(" %d", BT->Data);
	InorderTraversal(BT->Right);
	return;
}

2.找X,找最小和找最大

Position Find(BinTree BST, ElementType X){
	while (BST){
		if (BST->Data == X)break;
		else if (X > BST->Data)BST = BST->Right;
		else BST = BST->Left;
	}
	return BST;
}
Position FindMin(BinTree BST){
	if (!BST)return BST;
	while (BST->Left){
		BST = BST->Left;
	}
	return BST;
}
Position FindMax(BinTree BST){
	if (!BST)return BST;
	while (BST->Right){
		BST = BST->Right;
	}
	return BST;
}

2.1遞歸的思想就是


Position FindMax( BinTree BST ){
    if(!BST)return NULL;
    else if(!BST->Right)return BST;
    else return FindMax(BST->Right);
}

3.遞歸插入

3.1邊界條件:當這是一個空節點時,在此處插入
3.2小於向左遍歷;大於向右遍歷;一直到邊界條件
BST->Left = Insert(BST->Left, X);
含義:爲了掛接
當BST->Left不空時,返回的就是原來的BST-Left,那麼BST->Left=BST->Left一定成立;當BST->Left空時,返回的就是插入元素X後的BST->Left,原來BST->Left接着NULL的就會變成插入的X,此爲掛接

//遞歸插入
BinTree Insert(BinTree BST, ElementType X){
	//如果是一個空節點
	if (!BST){
		BST = (BinTree)malloc(sizeof(struct TNode));//既然爲空所以要生成一個
		BST->Data = X;
		BST->Left = NULL;
		BST->Right = NULL;
	}
	else{//一般情況
		if (X < BST->Data){//插入值小於節點,應該往左子樹中找位置
			BST->Left = Insert(BST->Left, X);//遞歸插入左子樹
		}
		else if (X > BST->Data){//插入值大於節點,應該往右子樹中找
			BST->Right = Insert(BST->Right, X);//遞歸插入右子樹
		}
		//如果相等說明X已經存在,什麼也不做
	}
	return BST;
}

4.遞歸刪除

1如果樹空那麼沒找到;
2如果樹沒空
2.1如果根不是刪除節點那麼根據排序,遞歸到它的某一子樹爲根的情況下重新判斷
2.2如果根是刪除節點那麼刪除

所以當根節點就是刪除節點時執行刪除;否則遞歸

4.1邊界條件

找到/沒找到

4.1.1如果最終樹爲空,說明沒找到(邊界1)

if (!BST){//邊界條件
		printf("Not Found\n");//如果最終樹爲空,說明沒有
	}

4.1.2如果當前樹還未空

4.1.2.1序號<根,根的左子樹掛接到 進入他的左子樹遞歸刪除 後重接的樹的根

if (X < BST->Data){
			BST->Left = Delete(BST->Left, X);//從左子樹遞歸刪除,掛接到父親的左孩子上
		}

4.1.2.2序號>根,根的右子樹掛接到 進入他的右子樹遞歸刪除 後重接的樹的根

else if (X > BST->Data){
			BST->Right = Delete(BST->Right, X);//從右子樹遞歸刪除,掛接到父親的右孩子上
		}

4.1.2.3否則就是序號=根,即找到了以要求刪除的節點爲根的樹(邊界2)

兩種情況:有兩個子節點,有一個子節點

4.1.2.3.1有兩個子節點(兩種方法)

用臨點(左子樹最大的/右子樹最小的,用findmax,findmin進入左右子樹尋找)代替,刪除臨點

4.1.2.3.1.1從右子樹中找最小的數填充刪除的節點

1.找右子樹最小
2.用最小填充刪除節點
3.遞歸刪除拿來填充的那個節點,並把根的右孩子掛接到 以根的右孩子爲根,遞歸刪除拿來填充的那個節點重接後的樹

if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從右子樹中找最小的數填充刪除的節點
				temp = FindMin(BST->Right);//找最小
				BST->Data = temp->Data;//填充刪除的節點
				BST->Right = Delete(BST->Right, temp->Data);//刪除拿來填充的那個節點,掛接到父親的左孩子上
			}
4.1.2.3.1.2從左子樹中找最大的數填充刪除的節點

1.找左子樹最大
2.用最大填充刪除節點
3.遞歸刪除拿來填充的那個節點,並把根的左孩子掛接到 以根的左孩子爲根,遞歸刪除拿來填充的那個節點重接後的樹

if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從左子樹中找最大的數填充刪除的節點
				temp = FindMax(BST->Left);//找最大
				BST->Data = temp->Data;//填充刪除的節點
				BST->Left = Delete(BST->Left, temp->Data);
4.1.2.3.2只有一個節點:重接

只需考慮重接,由於遞歸返回了重接後的樹的根,所以所有情況的樹到此都已經有了掛接的公式

1.1若刪除節點不是根節點,那麼在尋找該節點的過程中必定有掛接的步驟
1.2若刪除節點是根節點
1.2.1它有兩個孩子,那麼在刪除填充點的時候也必定有掛接的步驟
1.2.2它只有一個節點,那麼直接讓根變爲它的孩子即可,沒有需要掛接的部分

2.temp暫存刪除節點BST,BST變成重接過的樹
3.釋放刪除節點temp的空間

else{//只有一個子節點:重接
				temp = BST;
				if (!BST->Left){//只有右節點
					BST = BST->Right;//直接賦值就可以
				}
				else if (!BST->Right){//只有左節點
					BST = BST->Left;//直接賦值就可以
				}
				free(temp);//如果啥也沒有直接刪除就可以,當然上面兩種情況賦值後也要刪除
			}

總結:

BinTree Delete(BinTree BST, ElementType X){
	Position temp;
	if (!BST){//邊界條件
		printf("Not Found\n");//如果最終樹爲空,說明沒有
	}
	else{//這裏類似於插入重點在於找到後怎麼辦
		if (X < BST->Data){
			BST->Left = Delete(BST->Left, X);//從左子樹遞歸刪除,掛接到父親的左孩子上
		}
		else if (X > BST->Data){
			BST->Right = Delete(BST->Right, X);//從右子樹遞歸刪除,掛接到父親的右孩子上
		}
		else{//當前BST就是要刪除的節點(找到的邊界)
		
			/*兩種情況:有兩個子節點,有一個子節點*/
			//有兩個子節點用臨點(左子樹最大的/右子樹最小的,用findmax,findmin進入左右子樹尋找)代替,刪除臨點
			
			if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從右子樹中找最小的數填充刪除的節點
				temp = FindMin(BST->Right);//找最小
				BST->Data = temp->Data;//填充刪除的節點
				BST->Right = Delete(BST->Right, temp->Data);//刪除拿來填充的那個節點,掛接到父親的左孩子上
			}
			/*if (BST->Left && BST->Right){//要被刪除的節點有左右兩個孩子,就從左子樹中找最大的數填充刪除的節點
				temp = FindMax(BST->Left);//找最大
				BST->Data = temp->Data;//填充刪除的節點
				BST->Left = Delete(BST->Left, temp->Data);//刪除拿來填充的那個節點,掛接到父親的右孩子上*/
			else{//只有一個子節點:重接
				temp = BST;
				if (!BST->Left){//只有右節點
					BST = BST->Right;//直接賦值就可以
				}
				else if (!BST->Right){//只有左節點
					BST = BST->Left;//直接賦值就可以
				}
				free(temp);//如果啥也沒有直接刪除就可以,當然上面兩種情況賦值後也要刪除
			}
		}
	}
	return BST;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章