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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章