【算法】- 查找 - 二叉排序树


前言

编译语言:C++
编译器:VS2022


一、二叉排序树思想

当我们使用顺序查找、二分查找等顺序查找时发现,当我们需要插入和删除操作时,我们需要向移动数据。难道就没有一种查找方法既能查询又能应对插入和删除操作。二叉树查找就是这样的。我们利用二叉树左孩子比根节点小,右孩子比根节点大,来进行插入,因为这样插入我们使用中序遍历就成了有序的。OK,让我们一起来看看如何实现的二叉树吧

1.1、创建二叉树结构

首先我们先创建二叉树结构体,用于存放数据和左右孩子指针域

//创建二叉树结构
typedef struct BinaryTree
{
	int data;//用于存储数据
	struct BinaryTree* lchild, * rchild;//创建左孩子域和右孩子域
}BinaryTree,*BiTree;

1.2、查询二叉树

在我们进行插入之前,我们还得判断是否数组中已经有了改数,如果有了则返回,没有则进行插入操作所以我们还得先创建一个查询二叉树的函数,该函数用f来保存查询结束时上一个结点的地址,p用来返回查询到的地址。

//二叉树查找
//这里用f来存储查询结束上一个结点的位置
//p用来返回查询到的地址
int SearchBiTree(BiTree T, int key, BiTree f,BiTree* p)
{
	if (!T)
	{
		*p = f;
		return FALSE;
	}
	else if (T->data == key)
	{
		*p = T;
		return TRUE;
	}
	else if (key < T->data)
	{
		return SearchBiTree(T->lchild, key, T, p);
	}
	else
		return SearchBiTree(T->rchild, key, T, p);
}

1.3、插入二叉树

当我们查询发现并没有该数则进行插入操作,如果p为空则将s赋值为根节点,不为空就和根节点进行比较比根节点小就插入左孩子,反之,插入右孩子。

//插入二叉树
int InsertBiTree(BiTree* T,int key)
{
	BiTree p,s;
	if (!SearchBiTree(*T, key, NULL , &p))//在二叉树中查找数,如果没有则进行插入,有则返回
	{
		s = (BiTree)malloc(sizeof(BinaryTree));
		s->data = key;
		s->lchild = s->rchild = NULL;
		if (!p)
			*T = s;
		else if (key < p->data)
			p->lchild = s;
		else
			p->rchild = s;
		return OK;
	}
	else
		return ERROR;
}

1.3、删除二叉树

当我们需要删除二叉树时,首先我们先找到我们要删除的地址,那我们如何找到呢,这就和查询二叉树函数是一致的,通过比较K的大小来选择是查询左孩子还是右孩子,找到了就进行删除,这里的删除情况比较复杂,假设我们要删除的节点为P,P->lchild表示P的左孩子,P->rchild表示P的右孩子,我们先判断如果P没有左孩子,则就直接将P=P->rchild 。如果没有右孩子,则直接将P=P->lchild。如果左右孩子都存在,我们用代码来解释

int Delete(BiTree* T)
{
	BiTree q, s;
	if (!(*T)->lchild)//没有左孩子情况
	{
		q = *T;
		*T = (*T)->rchild;//将删除结点右孩子给*T
		free(q);
	}
	else if (!(*T)->rchild)//没有右孩子情况
	{
		q = *T;
		*T = (*T)->lchild;//将删除结点左孩子给*T
		free(q);
	}
	else
	{
		q = *T;
		s = (*T)->lchild;
		while (s->rchild)//找到删除结点的前驱
		{
			q = s;
			s = s->rchild;
		}
		(*T)->data = s->data;//将前驱转移到删除结点
		if (q != s)//这里的q是存储s的上一个结点
			q->rchild = s->lchild;//将重复的结点进行删除
		else
			q->lchild = s->lchild;//将重复的结点进行删除
		free(s);
		return OK;
	}
	return ERROR;
}

//二叉树删除操作
int DeleteBiTree(BiTree* T, int key)
{
	if (!T)
		return ERROR;
	else
	{
		if (key == (*T)->data)
			return Delete(T);//删除结点
		else if (key < (*T)->data)
			return DeleteBiTree(&(*T)->lchild, key);//继续从左孩子找,key
		else
			return DeleteBiTree(&(*T)->rchild, key);//继续从右孩子找,kye
	}
}

二、二叉排序树

#define MAXSIZE 10
#define ERROR 0
#define OK 1
#define FALSE 0
#define TRUE 1
#include <iostream>
#include <stdlib.h>
using namespace std;
//二叉树查找
//创建二叉树结构
typedef struct BinaryTree
{
	int data;//用于存储数据
	struct BinaryTree* lchild, * rchild;//创建左孩子域和右孩子域
}BinaryTree,*BiTree;
//二叉树查找
//这里用f来存储查询结束上一个结点的位置
//p用来返回查询到的地址
int SearchBiTree(BiTree T, int key, BiTree f,BiTree* p)
{
	if (!T)
	{
		*p = f;
		return FALSE;
	}
	else if (T->data == key)
	{
		*p = T;
		return TRUE;
	}
	else if (key < T->data)
	{
		return SearchBiTree(T->lchild, key, T, p);
	}
	else
		return SearchBiTree(T->rchild, key, T, p);
}
//插入二叉树
int InsertBiTree(BiTree* T,int key)
{
	BiTree p,s;
	if (!SearchBiTree(*T, key, NULL , &p))//在二叉树中查找数,如果没有则进行插入,有则返回
	{
		s = (BiTree)malloc(sizeof(BinaryTree));
		s->data = key;
		s->lchild = s->rchild = NULL;
		if (!p)
			*T = s;
		else if (key < p->data)
			p->lchild = s;
		else
			p->rchild = s;
		return OK;
	}
	else
		return ERROR;
}
//输出二叉树
int ShowBiTree(BiTree T)
{
	if (!T)
		return ERROR;
	else
	{
		ShowBiTree(T->lchild);
		printf("%d ", T->data);
		ShowBiTree(T->rchild);
	}
	return OK;
}
int Delete(BiTree* T)
{
	BiTree q, s;
	if (!(*T)->lchild)//没有左孩子情况
	{
		q = *T;
		*T = (*T)->rchild;//将删除结点右孩子给*T
		free(q);
	}
	else if (!(*T)->rchild)//没有右孩子情况
	{
		q = *T;
		*T = (*T)->lchild;//将删除结点左孩子给*T
		free(q);
	}
	else
	{
		q = *T;
		s = (*T)->lchild;
		while (s->rchild)//找到删除结点的前驱
		{
			q = s;
			s = s->rchild;
		}
		(*T)->data = s->data;//将前驱转移到删除结点
		if (q != s)//这里的q是存储s的上一个结点
			q->rchild = s->lchild;//将重复的结点进行删除
		else
			q->lchild = s->lchild;//将重复的结点进行删除
		free(s);
		return OK;
	}
	return ERROR;
}
//二叉树删除操作
int DeleteBiTree(BiTree* T, int key)
{
	if (!T)
		return ERROR;
	else
	{
		if (key == (*T)->data)
			return Delete(T);//删除结点
		else if (key < (*T)->data)
			return DeleteBiTree(&(*T)->lchild, key);//继续从左孩子找,key
		else
			return DeleteBiTree(&(*T)->rchild, key);//继续从右孩子找,kye
	}
}
int main()
{
	int i,k;
	BiTree T;//创建个树T
	T = NULL;
	k = 7;
	int arr[MAXSIZE + 1] = { 7,5,3,6,8,0,1,9,4,10,2 };//用于存储二叉树数据
	for (i = 0; i <= MAXSIZE; i++)//将数组arr中的数据插入到二叉树中
	{
		InsertBiTree(&T,arr[i]);
	}
	//输出二叉树
	ShowBiTree(T);
	printf("\n");
	//对二叉树删除结点操作
	DeleteBiTree(&T, k);
	ShowBiTree(T);
	return 0;
}

总结

二叉排序树以在执行插入或删除的时候有不用移动元素的优点,但是二叉排序树的查找性能取决于二叉排序树的形状,所以我们需将二叉排序树调整成平衡状态也就是平衡二叉树,这也是我们下节课将说明的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值