二叉搜索树(C语言实现)

这段代码实现了一个二叉搜索树(BST),包括插入元素、删除元素、查找最小和最大元素、按值查找以及中序遍历的功能。删除操作考虑了叶节点、单支节点和双支节点三种情况。此外,提供了菜单驱动的用户交互界面,方便进行各种操作。
摘要由CSDN通过智能技术生成

数据结构

typedef struct TreeNode {
	int data;//数据 
	struct TreeNode* left;//左孩子 
	struct TreeNode* right;//右孩子 
}BST, *BinTree;

 函数声明

void Insert(BinTree& BST, int x);//插入元素 
void Delete(BinTree& BST, int x);//删除元素 
BinTree FindMin(BinTree BST);//找寻最小值
BinTree FindMax(BinTree BST);//找寻最大值
BinTree FindElem(BinTree BST, int x);//按值查找
void MidOrder(BinTree BST);//中序遍历

void Insert_menu(BinTree& BST);
void Delete_menu(BinTree& BST);
void FindMin_menu(BinTree BST);
void FindMax_menu(BinTree BST);
void FindElem_menu(BinTree BST);
void MidOrder_menu(BinTree BST);

 插入元素

//插入元素 
void Insert(BinTree& BST, int x) {
	if (BST == NULL) {
		BST = (BinTree)malloc(sizeof(struct TreeNode));//构建结点 
		BST->data = x;
		BST->left = NULL;
		BST->right = NULL;
		return;
	}
	else if (x > BST->data) {//去右边找 
		Insert(BST->right, x);
	}

	else if (x < BST->data) {//去左边找 
		Insert(BST->left, x);
	}
}

删除元素(情况很多,代码有注释)

叶节点情况

  • 删除节点为根节点:直接删除,指向根节点的指针指向空,释放节点
  • 删除节点为非根节点:其父节点哪边有儿子,哪边指向空,释放节点
	if (node_temp->left == NULL && node_temp->right == NULL) {
		//若为根节点 
		if (node_temp == BST) {
			BST = NULL;//直接让根节点为空 
		}
		//非跟节点 
		else if (node_par->left == node_temp) { //若为左儿子 
			node_par->left = NULL;//让其父亲节点的左边为空 
		}
		else { //若为右儿子 
			node_par->right = NULL;//让其父亲节点的右边为空 
		}
	} 

单支节点情况

  • 删除节点为根节点:哪边有儿子,指向根节点的指针就指向有儿子的那一边,释放节点
  • 删除节点为非根节点:判断被删除节点是父节点的哪一边儿子,判断被删除节点拥有哪一边儿子
if (node_par->left == node_temp && temp->left != NULL) { 
				node_par->left = node_temp->left;//父亲指针绕过其左儿子直接指向其左儿子的左儿子 
			}
			if (node_par->left == node_temp && temp->right != NULL) {
				node_par->left = node_temp->right;//父亲指针直接绕过其左儿子,指向其左儿子的有儿子 
			}
			if (node_par->right == node_temp && temp->left != NULL) {
				node_par->right = node_temp->left;//父亲指针直接绕过其右儿子,指向其右儿子的左儿子 
			}
			if (node_par->right == node_temp && temp->right != NULL) {
				node_par->right = node_temp->right;//父亲指针直接绕过其右儿子,指向其右儿子的右儿子 
			}

 

双支节点情况

  • 临时变量记录此刻找到的节点
  • 去该节点右子树,找到最小的节点,记得记录最小节点的父节点
  • 值覆盖
  • 删除右子树的最小节点
    • 右子树有左儿子
    • 右子树无左儿子
else if (node_temp->left != NULL && node_temp->right != NULL) {
		BinTree temp = node_temp;
		node_temp = node_temp->right; 
		//找寻右子树的最小值 
		while (node_temp->right) {
			node_par = node_temp;//记录找到最小结点的父节点 
			node_temp = node_temp->left;
		}
		temp->data = node_temp->data;//数据覆盖
		//node_temp->right 因为找右子树的最小值,所以一定在最左边,且无左儿子,否则还可以找到更小的 
		if (node_par == temp) { //右子树只有一个元素 
			node_par = node_temp->right;
		} 
		else {
			node_par->left = node_temp->right;
		}
	}

void Delete(BinTree& BST, int x)
{
	if (BST == NULL) return;
	BinTree node_temp = BST;
	BinTree node_par = NULL;//记录被删除结点的父亲节点 
	BinTree temp = NULL;
	
	while (node_temp->data != x)
	{
		if (x > node_temp->data) {
			node_par = node_temp;
			node_temp = node_temp->right;
		}

		else if (x < node_temp->data) {
			node_par = node_temp;
			node_temp = node_temp->left;
		}
			
	}
	
	//无此值 退出 
	if (node_temp == NULL) return;
	
	//叶节点
	if (node_temp->left == NULL && node_temp->right == NULL) {
		//若为根节点 
		if (node_temp == BST) {
			BST = NULL;//直接让根节点为空 
		}
		//非跟节点 
		else if (node_par->left == node_temp) { //若为左儿子 
			node_par->left = NULL;//让其父亲节点的左边为空 
		}
		else { //若为右儿子 
			node_par->right = NULL;//让其父亲节点的右边为空 
		}
	} 
	
	//单支节点 
	else if (node_temp->left != NULL || node_temp->right != NULL) {
		//若为根节点 
		if (node_temp == BST) {
			if (node_temp->left != NULL) { //若有左儿子,原本指向根节点的指针指向其左儿子即可 
				BST = node_temp->left;
			}
			else { //若有右儿子 
				BST = node_temp->right; //若有右儿子,原本指向根节点的指针指向其右儿子即可
			}
		}
		//非根结点 
		else { //将其儿子给父亲 
			if (node_par->left == node_temp && temp->left != NULL) { 
				node_par->left = node_temp->left;//父亲指针绕过其左儿子直接指向其左儿子的左儿子 
			}
			if (node_par->left == node_temp && temp->right != NULL) {
				node_par->left = node_temp->right;//父亲指针直接绕过其左儿子,指向其左儿子的有儿子 
			}
			if (node_par->right == node_temp && temp->left != NULL) {
				node_par->right = node_temp->left;//父亲指针直接绕过其右儿子,指向其右儿子的左儿子 
			}
			if (node_par->right == node_temp && temp->right != NULL) {
				node_par->right = node_temp->right;//父亲指针直接绕过其右儿子,指向其右儿子的右儿子 
			}
		}
	}
	//双支节点 
	else if (node_temp->left != NULL && node_temp->right != NULL) {
		BinTree temp = node_temp;
		node_temp = node_temp->right; 
		//找寻右子树的最小值 
		while (node_temp->right) {
			node_par = node_temp;//记录找到最小结点的父节点 
			node_temp = node_temp->left;
		}
		temp->data = node_temp->data;//数据覆盖
		//node_temp->right 因为找右子树的最小值,所以一定在最左边,且无左儿子,否则还可以找到更小的 
		if (node_par == temp) { //右子树只有一个元素 
			node_par = node_temp->right;
		} 
		else {
			node_par->left = node_temp->right;
		}
	}
	
	free(node_temp);//释放节点 
}

返回最小元素的结点

BinTree FindMin(BinTree BST) {
	if (BST == NULL)
		return NULL;
	while (BST->left != NULL) {
		BST = BST->left;
	}
	return BST;
}

 返回最大元素的结点

BinTree FindMax(BinTree BST) {
	if (BST == NULL)
		return NULL;
	while (BST->right != NULL) {
		BST = BST->right;
	}
	return BST;
}

 按值查找

//按值查找 
BinTree FindElem(BinTree BST, int x) {
	if (BST == NULL) {
		return NULL;
	}
	else if (x > BST->data) {
		BST = FindElem(BST->right,x);
	}
	else if (x < BST->data) {
		BST = FindElem(BST->left, x);
	}
	return BST;
}

中序遍历

void MidOrder(BinTree BST) {
	if (BST != NULL) {
		MidOrder(BST->left);
		printf("%d", BST->data);
		MidOrder(BST->right);
	}
}

 

 源代码

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstdlib>
using namespace std;

typedef struct TreeNode {
	int data;//数据 
	struct TreeNode* left;//左孩子 
	struct TreeNode* right;//右孩子 
}BST, *BinTree;

void Insert(BinTree& BST, int x);//插入元素 
void Delete(BinTree& BST, int x);//删除元素 
BinTree FindMin(BinTree BST);
BinTree FindMax(BinTree BST);
BinTree FindElem(BinTree BST, int x);
void MidOrder(BinTree BST);

void Insert_menu(BinTree& BST);
void Delete_menu(BinTree& BST);
void FindMin_menu(BinTree BST);
void FindMax_menu(BinTree BST);
void FindElem_menu(BinTree BST);
void MidOrder_menu(BinTree BST);

void menu();

int main() {
	BinTree BST = NULL;//记得初始化为空指针,否则报错
	int max, min;
	int choice;
	while (true)
	{
		menu();
		scanf("%d", &choice);
		switch (choice)
		{
		case 0:
			exit(1);
			break;
		case 1:
			Insert_menu(BST);
			break;
		case 2:
			Delete_menu(BST); 
			break;
		case 3:
			MidOrder_menu(BST);
			printf("\n");
			break;
		case 4:
			FindElem_menu(BST);
			break;
		case 5:
			FindMax_menu(BST);
			break;
		case 6:
			FindMin_menu(BST);
			break;
		}
	}
	
	for (int i = 1; i <= 5; i++) {
		Insert(BST, i);
	}
	MidOrder(BST);
	cout << endl;
	BinTree temp;
	temp = FindMax(BST);
	cout << "Max = " << temp->data << endl;
	temp = FindMin(BST);
	cout << "Min = " << temp->data << endl;
	Delete(BST, 2);
	if (BST != NULL)
	MidOrder(BST);
	return 0;
}

void menu()
{
	printf("------------0.退出程序------------\n");
	printf("------------1.插入元素------------\n");
	printf("------------2.删除元素------------\n");
	printf("------------3.中序遍历------------\n");
	printf("------------4.查找元素------------\n");
	printf("------------5.最大元素------------\n");
	printf("------------6.最小元素------------\n");
}

//插入元素 
void Insert(BinTree& BST, int x) {
	if (BST == NULL) {
		BST = (BinTree)malloc(sizeof(struct TreeNode));//构建结点 
		BST->data = x;
		BST->left = NULL;
		BST->right = NULL;
		return;
	}
	else if (x > BST->data) {//去右边找 
		Insert(BST->right, x);
	}

	else if (x < BST->data) {//去左边找 
		Insert(BST->left, x);
	}
}

//删除元素 
void Delete(BinTree& BST, int x)
{
	if (BST == NULL) return;
	BinTree node_temp = BST;
	BinTree node_par = NULL;//记录被删除结点的父亲节点 
	BinTree temp = NULL;
	
	while (node_temp->data != x)
	{
		if (x > node_temp->data) {
			node_par = node_temp;
			node_temp = node_temp->right;
		}

		else if (x < node_temp->data) {
			node_par = node_temp;
			node_temp = node_temp->left;
		}
			
	}
	
	//无此值 退出 
	if (node_temp == NULL) return;
	
	//叶节点
	if (node_temp->left == NULL && node_temp->right == NULL) {
		//若为根节点 
		if (node_temp == BST) {
			BST = NULL;//直接让根节点为空 
		}
		//非跟节点 
		else if (node_par->left == node_temp) { //若为左儿子 
			node_par->left = NULL;//让其父亲节点的左边为空 
		}
		else { //若为右儿子 
			node_par->right = NULL;//让其父亲节点的右边为空 
		}
	} 
	
	//单支节点 
	else if (node_temp->left != NULL || node_temp->right != NULL) {
		//若为根节点 
		if (node_temp == BST) {
			if (node_temp->left != NULL) { //若有左儿子,原本指向根节点的指针指向其左儿子即可 
				BST = node_temp->left;
			}
			else { //若有右儿子 
				BST = node_temp->right; //若有右儿子,原本指向根节点的指针指向其右儿子即可
			}
		}
		//非根结点 
		else { //将其儿子给父亲 
			if (node_par->left == node_temp && temp->left != NULL) { 
				node_par->left = node_temp->left;//父亲指针绕过其左儿子直接指向其左儿子的左儿子 
			}
			if (node_par->left == node_temp && temp->right != NULL) {
				node_par->left = node_temp->right;//父亲指针直接绕过其左儿子,指向其左儿子的有儿子 
			}
			if (node_par->right == node_temp && temp->left != NULL) {
				node_par->right = node_temp->left;//父亲指针直接绕过其右儿子,指向其右儿子的左儿子 
			}
			if (node_par->right == node_temp && temp->right != NULL) {
				node_par->right = node_temp->right;//父亲指针直接绕过其右儿子,指向其右儿子的右儿子 
			}
		}
	}
	//双支节点 
	else if (node_temp->left != NULL && node_temp->right != NULL) {
		BinTree temp = node_temp;
		node_temp = node_temp->right; 
		//找寻右子树的最小值 
		while (node_temp->right) {
			node_par = node_temp;//记录找到最小结点的父节点 
			node_temp = node_temp->left;
		}
		temp->data = node_temp->data;//数据覆盖
		//node_temp->right 因为找右子树的最小值,所以一定在最左边,且无左儿子,否则还可以找到更小的 
		if (node_par == temp) { //右子树只有一个元素 
			node_par = node_temp->right;
		} 
		else {
			node_par->left = node_temp->right;
		}
	}
	
	free(node_temp);//释放节点 
}

//最小元素 
BinTree FindMin(BinTree BST) {
	if (BST == NULL)
		return NULL;
	while (BST->left != NULL) {
		BST = BST->left;
	}
	return BST;
}

//最大元素 
BinTree FindMax(BinTree BST) {
	if (BST == NULL)
		return NULL;
	while (BST->right != NULL) {
		BST = BST->right;
	}
	return BST;
}

//按值查找 
BinTree FindElem(BinTree BST, int x) {
	if (BST == NULL) {
		return NULL;
	}
	else if (x > BST->data) {
		BST = FindElem(BST->right,x);
	}
	else if (x < BST->data) {
		BST = FindElem(BST->left, x);
	}
	return BST;
}

//中序遍历 
void MidOrder(BinTree BST) {
	if (BST != NULL) {
		MidOrder(BST->left);
		printf("%d", BST->data);
		MidOrder(BST->right);
	}
}

//---------------------------------------
void Insert_menu(BinTree& BST)
{
	int n, x;
	printf("请输入您想要插入的元素个数\n");
	scanf("%d", &n);
	printf("请输入元素\n");
	for (int i = 0; i < n; i++)
	{
		scanf("%d", &x);
		Insert(BST, x);
	}
	printf("插入成功\n");
	system("pause");
	system("cls");
} 

void Delete_menu(BinTree& BST)
{
	printf("请输入您想删除的元素\n");
	int x; 
	scanf("%d", &x);
	Delete(BST,x);
	printf("删除成功\n");
	system("pause");
	system("cls");
}

void FindMin_menu(BinTree BST)
{
	BinTree temp = FindMin(BST);
	if (temp == NULL) 
	printf("树为空\n");
	else {
		printf("最小值为:%d", temp->data);
	}	
	system("pause");
	system("cls");
}

void FindMax_menu(BinTree BST)
{
	BinTree temp = FindMax(BST);
	if (temp == NULL) 
	printf("树为空\n");
	else {
		printf("最大值为:%d", temp->data);
	}
	system("pause");
	system("cls");
}

void FindElem_menu(BinTree BST)
{
	int x;
	printf("请输入您想要查询的值\n");
	scanf("%d", &x);
	BinTree temp = FindElem(BST,x);
	if (temp == NULL) 
	printf("无此值存在\n");
	else {
		printf("该值存在\n"); 
	}
	system("pause");
	system("cls");
}

void MidOrder_menu(BinTree BST) {
	MidOrder(BST);
	system("pause");
	system("cls");
}

运行结果

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值