数据结构C语言描述11(图文结合)--二叉搜索树(BST树)的实现(数据采用KV存储形式进行封装)

前言

  • 这个专栏将会用纯C实现常用的数据结构和简单的算法;
  • 有C基础即可跟着学习,代码均可运行;
  • 准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言实现的原因之一;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

什么是二叉搜索树

二叉搜索树(Binary Search Tree,BST)是一种特殊的二叉树数据结构,其中每个节点的值都大于其左子树中的任何节点的值,且小于其右子树中的任何节点的值

它的特点使得在搜索、插入和删除操作上具有高效性。

以下是一些关于二叉搜索树的重要特性:

  • 左子树中的所有节点的值都小于根节点的值。
  • 右子树中的所有节点的值都大于根节点的值。
  • 左右子树本身也是二叉搜索树。
  • 中序遍历有序。

由于这些特性,二叉搜索树可以用于高效地实现插入、搜索和删除操作。

  • 搜索操作可以在平均情况下以O(log n)的时间复杂度完成,其中n是树中节点的数量。
  • 然而,最坏情况下 ,树可能退化为链表,搜索操作的时间复杂度将变为O(n)
  • 插入操作的时间复杂度与搜索操作类似,平均情况下为O(log n),最坏情况下为O(n)
  • 删除操作的时间复杂度也是O(log n),最坏情况下为O(n)

BST书图示为:

代码实现

节点封装

节点封装,采用KV存储方式,数据在BST树中是存储K值 ,这里规定K值不重复。

cpp 复制代码
typedef struct Data {
	int key;
	char data[DATAMAX];
}Data;

typedef struct Node {
	Data* data;
	struct Node* lChild;
	struct Node* rChild;
}Node;

Data* creata_data(Data data)
{
	Data* new_data = (Data*)calloc(1, sizeof(Data));
	assert(new_data);
	new_data->key = data.key;
	strncpy(new_data->data, data.data, DATAMAX);
	return new_data;
}

Node* create_node(Data data)
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = creata_data(data);
	assert(node->data);
	return node;
}

插入节点

采用递归简历树。

cpp 复制代码
// 插入过程建树
void push_tree(Node** root, Data data)
{
	assert(root);

	// 树为NULL
	if (*root == NULL) {
		*root = create_node(data);
		return;
	}
	else {   // 树不为NULL
		if (data.key < (*root)->data->key) {
			push_tree(&(*root)->lChild, data);
		}
		else {   // > =默认也插在右边,但是一般这种kv存储,是不允许有重复值的
			push_tree(&(*root)->rChild, data);
		}
	}
}

删除节点

删除节点要注意,采用递归删除有5种情况,据图代码所示(清理可以参考代码随想录力扣题目解析:BST树的删除):

cpp 复制代码
// 删除
// 这里采用:左节点,最右节点
// 利用BST树的特点
// 5种情况
Node* erase_tree(Node* root, Data data)
{
	if (root == NULL) {
		return root;
	}

	if (root->data->key == data.key) {
		if (root->lChild == NULL && root->rChild == NULL) {
			free(root);
			root = NULL;
			return root;
		}
		else if (root->lChild == NULL && root->rChild != NULL) {
			Node* t = root;
			root = root->rChild;
			free(t);
			t = NULL;
			return root;
		}
		else if (root->lChild != NULL && root->rChild == NULL) {
			Node* t = root;
			root = root->lChild;
			free(t);
			t = NULL;
			return root;
		}
		else {
			Node* t = root->lChild;

			while (t->rChild) {
				t = t->rChild;
			}

			t->rChild = root->rChild;
			Node* temp = root;
			root = root->lChild;

			free(temp);

			return root;
		}
	}

	if (root && root->data->key > data.key) root->lChild = erase_tree(root->lChild, data);
	if (root && root->data->key < data.key) root->rChild = erase_tree(root->rChild, data);
}

输出(中序遍历有序)

BST树的中序遍历是有序的

cpp 复制代码
// 中序有序
void mid_travel(Node* root)
{
	if (root == NULL) {
		return;
	}

	mid_travel(root->lChild);
	printf("K: %d, V: %s\n", root->data->key, root->data->data);
	mid_travel(root->rChild);
}

总代码

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>

// 这里采用  kv 存储的方法,进行建立,  key也可以作为一个权重,具体情况需要结合业务

#define DATAMAX 20

typedef struct Data {
	int key;
	char data[DATAMAX];
}Data;

typedef struct Node {
	Data* data;
	struct Node* lChild;
	struct Node* rChild;
}Node;

Data* creata_data(Data data)
{
	Data* new_data = (Data*)calloc(1, sizeof(Data));
	assert(new_data);
	new_data->key = data.key;
	strncpy(new_data->data, data.data, DATAMAX);
	return new_data;
}

Node* create_node(Data data)
{
	Node* node = (Node*)calloc(1, sizeof(Node));
	assert(node);
	node->data = creata_data(data);
	assert(node->data);
	return node;
}

// 插入过程建树
void push_tree(Node** root, Data data)
{
	assert(root);

	// 树为NULL
	if (*root == NULL) {
		*root = create_node(data);
		return;
	}
	else {   // 树不为NULL
		if (data.key < (*root)->data->key) {
			push_tree(&(*root)->lChild, data);
		}
		else {   // > =默认也插在右边,但是一般这种kv存储,是不允许有重复值的
			push_tree(&(*root)->rChild, data);
		}
	}
}

// 删除
// 这里采用:左节点,最右节点
// 利用BST树的特点
// 5种情况
Node* erase_tree(Node* root, Data data)
{
	if (root == NULL) {
		return root;
	}

	if (root->data->key == data.key) {
		if (root->lChild == NULL && root->rChild == NULL) {
			free(root);
			root = NULL;
			return root;
		}
		else if (root->lChild == NULL && root->rChild != NULL) {
			Node* t = root;
			root = root->rChild;
			free(t);
			t = NULL;
			return root;
		}
		else if (root->lChild != NULL && root->rChild == NULL) {
			Node* t = root;
			root = root->lChild;
			free(t);
			t = NULL;
			return root;
		}
		else {
			Node* t = root->lChild;

			while (t->rChild) {
				t = t->rChild;
			}

			t->rChild = root->rChild;
			Node* temp = root;
			root = root->lChild;

			free(temp);

			return root;
		}
	}

	if (root && root->data->key > data.key) root->lChild = erase_tree(root->lChild, data);
	if (root && root->data->key < data.key) root->rChild = erase_tree(root->rChild, data);
}

// 中序有序
void mid_travel(Node* root)
{
	if (root == NULL) {
		return;
	}

	mid_travel(root->lChild);
	printf("K: %d, V: %s\n", root->data->key, root->data->data);
	mid_travel(root->rChild);
}

int main()
{
	Data data[10] = { {17, "yy"}, {9, "xx"}, {22, "zz"}, {2, "ll"}, {8, "tt"}, {33, "xh"}, {20, "tt"}, {18, "ee"}, {77, "zz"}, {10, "hh"} };

	Node* root = NULL;

	for (int i = 0; i < 10; i++) {
		push_tree(&root, data[i]);
	}

	mid_travel(root);
	
	int key = 22;
	
	Data temp = { 22, "tt" };
	
	erase_tree(root, temp);

	printf("*****************************\n");
	mid_travel(root);


	return 0;
}
相关推荐
Bingjia_Hu14 分钟前
使用 Python 的 pyttsx3 库进行文本转语音
开发语言·python·pyttsx3
xiao--xin14 分钟前
LeetCode100之括号生成(22)--Java
java·开发语言·算法·leetcode·回溯
雾里看山24 分钟前
C语言之结构体
c语言·开发语言·笔记
sun00770029 分钟前
c++开源协程库libgo介绍及使用,srs协程,boost协程 Boost::fiber
c++
百流35 分钟前
scala基础学习(数据类型)-集合
开发语言·学习·scala
dundunmm1 小时前
【论文阅读】SDA-FC: Bridging federated clustering and deep generative model
论文阅读·算法·数据挖掘·聚类·gan·联邦聚类
旧物有情1 小时前
蓝桥杯历届真题 # 封闭图形个数(C++,Java)
java·c++·蓝桥杯
SyntaxSage1 小时前
Lua语言的多线程编程
开发语言·后端·golang
深图智能1 小时前
OpenCV的TIF红外可见光融合算法
图像处理·人工智能·python·opencv·算法·计算机视觉
重生之我在20年代敲代码1 小时前
【C++入门】详解(中)
开发语言·c++·笔记