二叉排序树的创建和基本操作---C++实现

我们已经在之前的文章里将了树和二叉树,今天讲的二叉排序树也是二叉树的一种,不过具有以下性质

1.左子树上所有结点的关键字均小于根结点的关键字;

2.右子树上所有结点的关键字均大于根结点的关键字。

3.左子树和右子树又各是一棵二叉排序树

简单来说就是根结点的左子树都是比根结点的元素值要小,根结点右边的元素都比根结点要大

代码实现如下:

二叉排序树的结点信息和初始化

cpp 复制代码
#include<iostream>
#include<stdlib.h>
#include<stdbool.h>
using namespace std;
//二叉排序树结点
typedef struct BSTNode
{
	int key;//数据域
	struct BSTNode* lchild, * rchild;//指针域
}*BSTree,BSTNode;//BSTree表示整棵树 BSTNode表示结点
//初始化
void InitTree(BSTree* T)
{
	(*T) = NULL;
}

二叉排序树的插入和构建二叉树

1.若原二叉树为空,则直接插入结点;

2.如果关键字k小于根结点值,则插入左子树

3.如果关键字k大于根结点值,则插入右子树

cpp 复制代码
//插入操作
int BST_Insert(BSTree* T, int k)
{
	//空树,直接插入结点
	if ((*T) == NULL)
	{
		(*T) = (BSTNode*)malloc(sizeof(BSTNode));
		if (*T == NULL)
			return -1;//插入失败
		(*T)->key = k;
		(*T)->lchild = NULL; //左孩子为空
		(*T)->rchild = NULL; //右孩子为空
		return 1;//插入成功
	}
	else if (k == (*T)->key)
		return -1; //如果插入相同的则直接返回
	else if (k > (*T)->key)
		return BST_Insert(&(*T)->rchild, k);//因为是要修改右子树,所以要取地址
	else
		return BST_Insert(&(*T)->lchild, k);
	return -1;
}
//构建二叉树
bool Creat_BSTree(BSTree* T, int arr[], int len)
{
	int i = 0;
	while (i < len)
	{
		BST_Insert(T, arr[i]);
		i++;
	}
	return true;
}

二叉排序树的查找(递归方式)

cpp 复制代码
//查找二叉树
BSTree BST_Search(BSTree T,int k)
{
	if (T == NULL)
		return NULL;//空树查找失败
	while (T != NULL && T->key != k)
	{
		if (k > T->key) //k大于根结点
			T = T->rchild;
		else
			T = T->lchild;
	}
	return T;
}

二叉排序树的删除

思想:

先搜索找到目标结点

1.如果被删除的结点z是叶子结点,则直接删除,不回破坏二叉排序树的性质

2.如果结点z只有一棵左子树或右子树,则让z的子树称为z父结点的子树,代替z的位置

3.如果结点z有左、右两棵子树,则令z的直接后继(或直接前驱)代替z,然后从二叉排序树中删去这个直接后继(或直接前驱),这样就转换成了第一后第二种情况

注意:

z的前驱:z的左子树中最右下的结点(该结点在左子树中一定最大)

z的后继:z的右子树中最左下的结点(该结点在右子树中一定最小)

cpp 复制代码
//删除二叉树
int Delete_BSTNode(BSTree* T, int k)
{
	if (*T == NULL)
		return -1;//空树无法删除

	BSTNode* p = BST_Search(*T, k);//查找当前元素
	BSTNode* parent = BST_SearchF((*T), k);//当前元素的父结点

	if (p == NULL)//没有该元素
		return -1;

	else if (p->lchild == NULL && p->rchild == NULL)//如果要删除叶子结点
	{
		if (parent == NULL)//如果只有一个结点
		{
			free(*T);
			*T = NULL;
		}
		else if (parent->lchild == p)//删除p
		{
			parent->lchild = NULL;
			free(p);
		}
		else
		{
			parent->rchild = NULL;
			free(p);
		}
		return 1;//删除成功
	}
	else if (p->lchild == NULL || p->rchild == NULL)//如果要删除单支结点(只有左孩子或者只有右孩子)
	{
		if (parent->lchild == p)//如果p为父结点的左孩子
		{
			if (p->lchild == NULL && p->rchild != NULL)//左孩子为空,右孩子不为空
			{
				parent->lchild = p->rchild;
				free(p);
				return 1;//删除成功
			}
			else if (p->lchild != NULL && p->rchild == NULL)//左孩子不为空,右孩子为空
			{
				parent->lchild = p->lchild;
				free(p);
				return 1;//删除成功
			}
		}
		if (parent->rchild == p)//如果p为父结点的右孩子
		{
			if (p->lchild == NULL && p->rchild != NULL)//左孩子为空,右孩子不为空
			{
				parent->rchild = p->rchild;
				free(p);
				return 1;//删除成功
			}
			else if (p->lchild != NULL && p->rchild == NULL)//左孩子不为空,右孩子为空
			{
				parent->rchild = p->lchild;
				free(p);
				return 1;//删除成功
			}
		}
	}
	else if (p->lchild != NULL && p->rchild != NULL)//如果要删除的结点有左右孩子
	{
		//查找要删除结点的直接后继(右孩子的第一个访问元素)
		BSTNode* q = p->rchild;
		while (q->lchild != NULL)
			q = q->lchild;
		p->key = q->key;

		//当前结点的直接后继的父结点
		BSTNode* currpar = BST_SearchF(*T, q->key);
		if (currpar->lchild == q)
		{
			if (q->rchild != NULL)
				currpar->lchild = q->rchild;
			else
				currpar->lchild = NULL;
			free(q);
		}
		else if (currpar->rchild == q)
		{
			if (q->rchild != NULL)
				currpar->rchild = q->rchild;
			else
				currpar->rchild = NULL;
			free(q);
		}
		return 1;//删除成功
	}
	return -1;//删除失败
}

main函数

cpp 复制代码
int main()
{
	//二叉树元素
	int arr[10] = { 60,58,98,45,65,24,37,49,86,82 };
	int len = sizeof(arr) / sizeof(arr[0]);//数组的长度
	//定义二叉树
	BSTree T;
	InitTree(&T);//初始化二叉树
	//构建二叉树
	Creat_BSTree(&T, arr,len);
	
	//查找二叉树结点(非递归算法)
	BSTNode * p = BST_Search(T,arr[9]);
	cout << "key = " << p->key << endl;//打印测试

	//删除二叉树结点
	Delete_BSTNode(&T, arr[9]);

	return 0;
}

查找效率分析:

1.若树高h,找到最下层的一个结点需要对比h次

2.最好情况:n个结点的二叉树最小高度为log2n + 1,平均查找长度为O(log2n)

3.最坏情况:每个结点只有一个分支,树高h=结点数n。则平均查找长度为O(n)

相关推荐
仰泳的熊猫1 小时前
1061 Dating
数据结构·c++·算法·pat考试
Fcy6481 小时前
二叉搜索树(C++实现)
开发语言·数据结构·c++·二叉搜索树
CoderYanger1 小时前
A.每日一题——1523. 在区间范围内统计奇数数目
java·数据结构·算法·leetcode·职场和发展
surtr12 小时前
Round 1019(div2) CD
数据结构·c++·算法·贪心算法·stl
Hcoco_me2 小时前
大模型面试题14:K-means聚类算法全解析(通用场景+深度拓展)
算法·kmeans·聚类
Tim_102 小时前
【C++入门】02、C++程序初识
开发语言·c++
Jay20021112 小时前
【机器学习】30 基于内容的过滤算法
人工智能·算法·机器学习
冰西瓜6002 小时前
分治(二)算法设计与分析 国科大
数据结构·算法