【数据结构】二叉搜索树的基本操作(第二遍)


总结一下二叉搜索树的删除


二叉搜索树的删除分为以下几种情况:

1.要删除的结点是叶节点
a.要删除的结点是根节点
b.要删除的结点非根节点
2.要删除的结点左子树为空
a.要删除的结点是根节点
b.要删除的结点非根节点
3.要删除的结点右子树为空
a.要删除的结点是根节点
b.要删除的结点非根节点
4.要删除的结点左右子树都不为空
a.要删除的结点是根节点
b.要删除的结点非根节点
如果要删除的结点的左右子树都不为空,那么,要么找出当前
结点左子树中最大的结点与该结点的值进行交换,然后删除那
个最大的结点;或者,找出当前结点右子树中最小的结点与该
结点进行交换,然后删除那个最小的结点


这里面,其他都是把当前结点的父节点指向当前结点的下一个结点或者指向空,
只有当结点左右子树都不为空时才需要特别考虑

BSTree.h


#pragma once

typedef char BSearchTreeType;

typedef struct BSearchNode{
	BSearchTreeType key;
	struct BSearchNode* lchild;
	struct BSearchNode* rchild;
}BSearchNode;

/*初始化*/
void BSearchTreeInit(BSearchNode** root);

/*
**插入
**递归和非递归
*/
void BSearchTreeInsert(BSearchNode** root, BSearchTreeType value);
/*非递归版本*/
void BSearchTreeInsertByLoop(BSearchNode** root, BSearchTreeType value);

/*
**查找
**递归和非递归
*/
BSearchNode* BSearchTreeFind(BSearchNode* root, BSearchTreeType to_find);
/*非递归*/
BSearchNode* BSearchTreeFindByLoop(BSearchNode* root, BSearchTreeType to_find);

/*删除*/
void BSearchTreeRemove(BSearchNode** root, BSearchTreeType to_del);
/*非递归*/
void BSearchTreeRemoveByLoop(BSearchNode** root, BSearchTreeType to_del);




BSTree.c


#define _CRT_SECURE_NO_WARNINGS 1
#include"BinSTree.h"
#include<stdio.h>
#include<stdlib.h>

/*初始化*/
void BSearchTreeInit(BSearchNode** root) {
	if (root == NULL) {
		return;
	}
	*root = NULL;
}

BSearchNode* CreateSearchNode(BSearchTreeType value) {
	BSearchNode* new_node = (BSearchNode*)malloc(sizeof(BSearchNode));
	if (new_node != NULL) {
		new_node->key = value;
		new_node->lchild = NULL;
		new_node->rchild = NULL;
		return new_node;
	}
}

/*
**插入
**递归和非递归
*/
void BSearchTreeInsertByLoop(BSearchNode** root, BSearchTreeType value) {
	if (root == NULL) {
		return;
	}
	if (*root == NULL) {
		*root = CreateSearchNode(value);
		return;
	}
	else {
		/*如果根节点不为空*/
		BSearchNode* cur = *root;
		BSearchNode* parent = NULL;
		/*
		**如果更改当前结点的左右孩子结点的指针,即使用的是一级指针也可以更改
		**因为一级指针是指向结构体的,一级指针可以更改指针所指向的内容,而二级指针可以更改指针所指向的内容
		*/
		while (cur != NULL) {
			if (cur->key > value) {
				parent = cur;
				cur = cur->lchild;
			}
			else if (cur->key < value) {
				parent = cur;
				cur = parent->rchild;
			}
			else {
				/*有相同的值则不插入直接返回*/
				return;
			}
		}
		if (parent->key > value) {
			parent->lchild = CreateSearchNode(value);
		}
		else {
			parent->rchild = CreateSearchNode(value);
		}
	}//根节点不为空
	return;
}

/*递归版本*/
void BSearchTreeInsert(BSearchNode** root, BSearchTreeType value) {
	if (root == NULL) {
		return;
	}
	if (*root == NULL) {
		/*当前结点为空,表示找到了插入位置*/
		*root = CreateSearchNode(value);
		return *root;
	}
	if ((*root)->key < value) {
		BSearchTreeInsert(&(*root)->rchild, value);
	}
	else if ((*root)->key > value) {
		BSearchTreeInsert(&(*root)->lchild, value);
	}
	else {
		/*这样是错误的,不能插入*/
		return;
	}
}

/*
**查找
**递归和非递归
*/
BSearchNode* BSearchTreeFind(BSearchNode* root, BSearchTreeType to_find) {
	if (root == NULL) {
		return NULL;
	}
	if (root->key > to_find) {
		BSearchTreeFind(root->lchild, to_find);
	}
	else if (root->key < to_find) {
		BSearchTreeFind(root->rchild, to_find);
	}
	else {
		return root;
	}
}

/*非递归*/
BSearchNode* BSearchTreeFindByLoop(BSearchNode* root, BSearchTreeType to_find) {
	if (root == NULL) {
		return;
	}
	while (root) {
		if (root->key > to_find) {
			root = root->lchild;
		}
		else if (root->key < to_find) {
			root = root->rchild;
		}
		else {
			return root;
		}
	}//循环结束,表示没找到
	return NULL;
}

/*销毁结点*/
void DestoryBSTNode(BSearchNode* to_del) {
	if (to_del == NULL) {
		return;
	}
	free(to_del);
}


/*删除某个结点,递归版本*/
void BSearchTreeRemove(BSearchNode** root, BSearchTreeType to_del) {
	if (root == NULL) {
		return;
	}
	if (*root == NULL) {
		/*没找到要删除的结点*/
		printf("该元素在树中不存在!");
		return;
	}
	if ((*root)->key < to_del) {
		BSearchTreeRemove(&(*root)->rchild, to_del);
	}
	else if ((*root)->key > to_del) {
		BSearchTreeRemove(&(*root)->lchild, to_del);
	}
	else {
		/*开始删除*/
		BSearchNode* remove = *root;
		if (remove->lchild == NULL && remove->rchild == NULL) {
			*root = NULL;
			DestoryBSTNode(remove);
			remove = NULL;
			return;
		}
		else if (remove->lchild != NULL &&remove->rchild == NULL) {
			*root = remove->lchild;
			DestoryBSTNode(remove);
			remove = NULL;
			return;
		}
		else if (remove->lchild == NULL && remove->rchild != NULL) {
			*root = remove->rchild;
			DestoryBSTNode(remove);
			remove = NULL;
			return;
		}
		else {
			BSearchNode* min_node = remove->rchild;
			BSearchNode* parent = NULL;
			while (min_node->lchild) {
				parent = min_node;
				min_node = min_node->lchild;
			}
			remove->key = min_node->key;
			BSearchTreeRemove(&remove->rchild, min_node->key);
			return;
		}
	}
}

/*删除结点*/
void Delete_Node(BSearchNode** parent, BSearchNode* to_remove, int flag) {
	if (parent == NULL) {
		return;
	}
	if (flag == 1) {
		/*
		**当前结点为叶结点
		**找出要删除的结点是在父节点的哪一边
		*/
		if ((*parent)->key > to_remove->key) {
			(*parent)->lchild = NULL;
		}
		else {
			(*parent)->rchild = NULL;
		}
	}
	else if (flag == 2) {
		/*当前结点左子树不为空*/
		if ((*parent)->key > to_remove->key) {
			(*parent)->lchild = to_remove->lchild;
		}
		else {
			(*parent)->rchild = to_remove->lchild;
		}
	}
	else if (flag == 3) {
		/*当前结点右子树不为空*/
		/*当前结点左子树不为空*/
		if ((*parent)->key > to_remove->key) {
			(*parent)->lchild = to_remove->rchild;
		}
		else {
			(*parent)->rchild = to_remove->rchild;
		}
	}
	else if(flag == 4) {
		/*当前结点左右子树都不为空*/
		/*找出要删除的结点的右子树中最小的值*/
		BSearchNode* cur = to_remove->rchild;
		*parent = NULL;
		while (cur->lchild) {
			*parent = cur;
			cur = cur->lchild;
		}
		to_remove->key = cur->key;
		if (*parent == NULL) {
			to_remove->rchild = cur->rchild;
		}
		else {
			(*parent)->lchild = cur->rchild;
		}
		DestoryBSTNode(cur);
		cur = NULL;
		return;
	}
	else {
		/*标志位传入错误*/
		return;
	}
	/*销毁要删除的结点*/
	DestoryBSTNode(to_remove);
	to_remove = NULL;
}

/*删除根结点*/
void Delete_root(BSearchNode** root, int flag) {
	if (root == NULL) {
		return;
	}
	if (*root == NULL) {
		return;
	}
	BSearchNode* _delete = *root;
	if (flag == 1) {
		//根节点没有左右结点
		*root = NULL;
	}
	else if (flag == 2)  {
		/*根节点有左子树*/
		*root = (*root)->lchild;
	}
	else if (flag == 3) {
		//根节点有右子树
		*root = (*root)->rchild;
	}
	else if (flag == 4) {
		//根节点左右子树都有
		//在根节点的右子树中找到结点最小的值
		BSearchNode* cur = (*root)->rchild;
		BSearchNode* parent = NULL;
		while (cur->lchild) {
			parent = cur;
			cur = cur->lchild;
		}
		(*root)->key = cur->key;
		if (parent == NULL) {
			(*root)->rchild = cur->rchild;
		}
		else {
			parent->lchild = cur->rchild;
		}
		DestoryBSTNode(cur);
		cur = NULL;
		return;
	}
	else {
		//标志位传入错误
		printf("标志位传入错误!\n");
		return;
	}
	DestoryBSTNode(_delete);
	_delete = NULL;
}

/*删除重新写一遍非递归版本的*/
void BSearchTreeRemove(BSearchNode** root, BSearchTreeType to_del) {
	if (root == NULL) {
		return;
	}
	if (*root == NULL) {
		return;
	}

	BSearchNode* to_remove = *root;
	BSearchNode* parent = NULL;

	while (to_remove) {
		if (to_remove->key > to_del) {
			parent = to_remove;
			to_remove = to_remove->lchild;
		}
		else if (to_remove->key < to_del) {
			parent = to_remove;
			to_remove = to_remove->rchild;
		}
		else {
			break;
		}
	}
	/*设立标志位*/
	int flag = 0;
	if (to_remove == NULL) {
		printf("要删除的结点不存在!\n");
		return;
	}
	else {
		/*找到要删除的结点了,保存在remove里面*/
		if (to_remove->lchild == NULL && to_remove->rchild == NULL) {
			//当前要删除的结点是叶节点
			flag = 1;
			if (parent == NULL) {
				//要删除的是根节点
				Delete_root(root, flag);
			}
			else {
				/*要删除的结点非根节点*/
				Delete_Node(&parent, to_remove, flag);
			}
		}
		else if (to_remove->lchild != NULL && to_remove->rchild == NULL) {
			flag = 2;
			//当前要删除的结点左子树不为空
			if (parent == NULL) {
				Delete_root(root, flag);
			}
			else {
				Delete_Node(&parent, to_remove, flag);
			}
		}
		else if (to_remove->lchild == NULL && to_remove->rchild != NULL) {
			flag = 3;
			//当前要删除的结点右子树不为空
			if (parent == NULL) {
				Delete_root(root, flag);
			}
			else {
				Delete_Node(&parent, to_remove, flag);
			}
		}
		else {
			flag = 4;
			//当前要删除的结点左右子树都不为空
			if (parent == NULL) {
				Delete_root(root, flag);
			}
			else {
				Delete_Node(&parent, to_remove, flag);
			}
		}
	}
}



test.c


#define _CRT_SECURE_NO_WARNINGS 1
#include"BinSTree.h"
#include<stdio.h>
#include<stdlib.h>

#define TESTHEAD printf("-----------------%s---------------\n",__FUNCTION__)

/*前序遍历二叉树*/
void PreOrder(BSearchNode* root) {
	if (root == NULL) {
		return;
	}
	printf("%c ", root->key);
	PreOrder(root->lchild);
	PreOrder(root->rchild);
}

void InOrder(BSearchNode* root) {
	if (root == NULL) {
		return;
	}
	InOrder(root->lchild);
	printf("%c ", root->key);
	InOrder(root->rchild);
}

void TestInsert() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	BSearchTreeInsert(&root, 'd');
	BSearchTreeInsert(&root, 'b');
	BSearchTreeInsert(&root, 'f');
	BSearchTreeInsert(&root, 'c');
	BSearchTreeInsert(&root, 'a');
	BSearchTreeInsert(&root, 'e');
	BSearchTreeInsert(&root, 'h');
	BSearchTreeInsert(&root, 'g');
	BSearchTreeInsert(&root, 'i');

	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
}

void TestInsertByLoop() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	BSearchTreeInsertByLoop(&root, 'd');
	BSearchTreeInsertByLoop(&root, 'b');
	BSearchTreeInsertByLoop(&root, 'f');
	BSearchTreeInsertByLoop(&root, 'c');
	BSearchTreeInsertByLoop(&root, 'a');
	BSearchTreeInsertByLoop(&root, 'e');
	BSearchTreeInsertByLoop(&root, 'h');
	BSearchTreeInsertByLoop(&root, 'g');
	BSearchTreeInsertByLoop(&root, 'i');
	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
}

void TestFind() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	BSearchTreeInsertByLoop(&root, 'd');
	BSearchTreeInsertByLoop(&root, 'b');
	BSearchTreeInsertByLoop(&root, 'f');
	BSearchTreeInsertByLoop(&root, 'c');
	BSearchTreeInsertByLoop(&root, 'a');
	BSearchTreeInsertByLoop(&root, 'e');
	BSearchTreeInsertByLoop(&root, 'h');
	BSearchTreeInsertByLoop(&root, 'g');
	BSearchTreeInsertByLoop(&root, 'i');

	BSearchNode* find_node = BSearchTreeFind(root, 'c');
	printf("expect %p, actual:%p\n", root->lchild->rchild, find_node);
}

void TestFindByLoop() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	BSearchTreeInsertByLoop(&root, 'd');
	BSearchTreeInsertByLoop(&root, 'b');
	BSearchTreeInsertByLoop(&root, 'f');
	BSearchTreeInsertByLoop(&root, 'c');
	BSearchTreeInsertByLoop(&root, 'a');
	BSearchTreeInsertByLoop(&root, 'e');
	BSearchTreeInsertByLoop(&root, 'h');
	BSearchTreeInsertByLoop(&root, 'g');
	BSearchTreeInsertByLoop(&root, 'i');
	BSearchNode* find_node = BSearchTreeFindByLoop(root, 'c');
	printf("expect %p, actual:%p\n", root->lchild->rchild, find_node);
}

void TestRemoveByLoop() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;

	//测试删除根节点
	// 1.树只有一个根节点
	BSearchTreeInsertByLoop(&root, 'd');
//	BSearchTreeRemoveByLoop(&root, 'd');

	// 2.根节点只有左子树
	BSearchTreeInsertByLoop(&root, 'b');
//	BSearchTreeRemoveByLoop(&root, 'd');

	// 3.根节点只有一个右子树
	BSearchTreeInsertByLoop(&root, 'f');
//	BSearchTreeRemoveByLoop(&root, 'd');

	// 4.根节点左右都有
//	BSearchTreeRemoveByLoop(&root, 'd');

	//再插入几个结点
	BSearchTreeInsertByLoop(&root, 'a');
	BSearchTreeInsertByLoop(&root, 'c');
	BSearchTreeInsertByLoop(&root, 'h');
	BSearchTreeInsertByLoop(&root, 'i');

	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");

	//测试删除正常结点
	//1.删除叶节点

	//BSearchTreeRemoveByLoop(&root, 'i');
	//PreOrder(root);
	//printf("\n");
	//InOrder(root);
	//printf("\n");


	//2.删除只有左子树的结点
	/*BSearchTreeRemoveByLoop(&root, '');
	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
*/
	//删除只有右子树的结点
	/*BSearchTreeRemoveByLoop(&root, 'f');
	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");*/

	//删除左右子树都有的结点
	BSearchTreeRemoveByLoop(&root, 'b');
	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");

	//删除不存在的结点
	BSearchTreeRemoveByLoop(&root, 'g');
}
 
void TestRemove() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	//测试根节点
	//1.根节点没有左右子树
	BSearchTreeInsert(&root, 'd');
	//BSearchTreeRemove(&root, 'd');
	//PreOrder(root);
	//InOrder(root);



	//2.根节点有左子树
	BSearchTreeInsert(&root, 'b');
//	BSearchTreeRemove(&root, 'd');
	/*PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");*/

	//3.根节点有右子树
	BSearchTreeInsert(&root, 'f');
	//BSearchTreeRemove(&root, 'd');
	//PreOrder(root);
	//printf("\n");
	//InOrder(root);
	//printf("\n");
	//4.根节点左右子树都有
//	BSearchTreeRemove(&root, 'd');
	//PreOrder(root);
	//printf("\n");
	//InOrder(root);
	//printf("\n");

	//测试非根节点
	BSearchTreeInsert(&root, 'a');
	BSearchTreeInsert(&root, 'c');
	BSearchTreeInsert(&root, 'g');
	BSearchTreeInsert(&root, 'h');

	//1.叶节点
	//BSearchTreeRemove(&root, 'g');
	//PreOrder(root);
	//printf("\n");
	//InOrder(root);
	//printf("\n");
	
	//2.只有左子树
	//BSearchTreeRemove(&root, 'h');

	//3.只有右子树
//	BSearchTreeRemove(&root, 'f');

	//4.左右子树都有
	BSearchTreeRemove(&root, 'b');

	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
}

void TestRemove2() {
	BSearchNode* root;
	BSearchTreeInit(&root);
	TESTHEAD;
	//BSearchTreeInsert(&root, 'd');
	//BSearchTreeInsert(&root, 'b');
	//BSearchTreeInsert(&root, 'a');
	//BSearchTreeInsert(&root, 'c');
	/*BSearchTreeInsert(&root, 'h');
	BSearchTreeInsert(&root, 'g');*/
	/*BSearchTreeInsert(&root, 'h');
	BSearchTreeInsert(&root, 'f');
	BSearchTreeInsert(&root, 'g');*/
	BSearchTreeInsert(&root, 'i');
	BSearchTreeInsert(&root, 'e');
	BSearchTreeInsert(&root, 'k');
	BSearchTreeInsert(&root, 'b');
	BSearchTreeInsert(&root, 'h');
	BSearchTreeInsert(&root, 'd');
	BSearchTreeInsert(&root, 'g');
	BSearchTreeInsert(&root, 'f');






	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");

	//根节点	
	// 1. 根节点左右为空
//	BSearchTreeRemove2(&root, 'a');

	// 2. 根节点有左子树
//	BSearchTreeRemove2(&root, 'd');

	// 3. 根节点有右子树
//	BSearchTreeRemove2(&root, 'd');

	// 4. 根节点左右子树都有
	//BSearchTreeRemove2(&root, 'd');

	//不是根节点
	// 1. 节点左右为空
//	BSearchTreeRemove2(&root, 'c');

	// 2. 节点有左子树
//	BSearchTreeRemove2(&root, 'f');

	// 3. 节点有右子树
//	BSearchTreeRemove(&root, 'f');

	// 4. 节点左右子树都有
	BSearchTreeRemove2(&root, 'e');
	PreOrder(root);
	printf("\n");
	InOrder(root);
	printf("\n");
}

int main() {
	TestInsert();
	TestInsertByLoop();
	TestFind();
	TestFindByLoop();
	TestRemoveByLoop();
	TestRemove2();
	system("pause");
	return 0;
}

删除结点那个把里面许多的代码用了函数实现,函数写起来其实也不难,但是有些地方细节还是没有注意到位,调试

的时候还是出了很多bug,这是第二次写二叉搜索树了,删除部分写了好几遍了,也算是熟悉了,写下博客记录下来


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值