基本数据结构--平衡二叉搜索树之红黑树示例代码
红黑树的规则。红黑树的每个节点有颜色(红或黑),满足以下性质:
- 每个节点是红或黑。
- 根节点是黑的。
- 叶子节点(NIL节点)是黑的。
- 红节点的子节点必须是黑的。
- 从任一节点到其所有后代叶子节点的路径包含相同数量的黑节点。
#include <stdlib.h>typedef enum { RED, BLACK } Color;typedef struct RBNode {void *data;Color color;struct RBNode *left, *right, *parent;
} RBNode;typedef struct {RBNode *root;int (*compare)(const void*, const void*);void (*data_free)(void*); // 必须由用户初始化
} RBTree;// 创建新节点(默认红色)
RBNode* create_node(void *data) {RBNode* node = (RBNode*)malloc(sizeof(RBNode));node->data = data;node->color = RED;node->left = node->right = node->parent = NULL;return node;
}// 左旋操作
void left_rotate(RBTree *t, RBNode *x) {RBNode *y = x->right;x->right = y->left;if (y->left) y->left->parent = x;y->parent = x->parent;if (!x->parent)t->root = y;else if (x == x->parent->left)x->parent->left = y;else x->parent->right = y;y->left = x;x->parent = y;
}// 右旋操作
void right_rotate(RBTree *t, RBNode *x) {RBNode *y = x->left;x->left = y->right;if (y->right)y->right->parent = x;y->parent = x->parent;if (!x->parent)t->root = y;else if (x == x->parent->left)x->parent->left = y;else x->parent->right = y;y->right = x;x->parent = y;
}// 插入修复
void insert_fixup(RBTree *t, RBNode *z) {while (z->parent && z->parent->color == RED) {RBNode *parent = z->parent;RBNode *grandparent = parent->parent; if (parent == grandparent->left) {RBNode *uncle = grandparent->right;if (uncle && uncle->color == RED) {// Case 1: uncle存在且为红色 parent->color = BLACK;uncle->color = BLACK;grandparent->color = RED;z = grandparent;} else {// Case 2/3: uncle为黑色或不存在 if (z == parent->right) {z = parent;left_rotate(t, z);parent = z->parent;}// Case 3 parent->color = BLACK;grandparent->color = RED;right_rotate(t, grandparent);}} else {RBNode *uncle = grandparent->left;if (uncle && uncle->color == RED) {parent->color = BLACK;uncle->color = BLACK;grandparent->color = RED;z = grandparent;} else {if (z == parent->left) {z = parent;right_rotate(t, z);parent = z->parent;}parent->color = BLACK;grandparent->color = RED;left_rotate(t, grandparent);}}}t->root->color = BLACK;
}// 公共插入接口
void rb_insert(RBTree *t, void *data) {RBNode *z = create_node(data);RBNode *y = NULL, *x = t->root;while (x) {y = x;int cmp = t->compare(z->data, x->data);if (cmp < 0)x = x->left;else x = x->right;}z->parent = y;if (!y)t->root = z;else if (t->compare(z->data, y->data) < 0)y->left = z;else y->right = z;insert_fixup(t, z);
}// 删除修复
void delete_fixup(RBTree *t, RBNode *x) {while (x != t->root && (x == NULL || x->color == BLACK)) {if (x == x->parent->left) {RBNode *w = x->parent->right;if (w->color == RED) {// Case 1: 兄弟是红色 w->color = BLACK;x->parent->color = RED;left_rotate(t, x->parent);w = x->parent->right;}if ((w->left == NULL || w->left->color == BLACK) &&(w->right == NULL || w->right->color == BLACK)) {// Case 2: 兄弟的两个孩子都是黑色 w->color = RED;x = x->parent;} else {if (w->right == NULL || w->right->color == BLACK) {// Case 3: 兄弟左孩子红,右孩子黑 if (w->left) w->left->color = BLACK;w->color = RED;right_rotate(t, w);w = x->parent->right;}// Case 4: 兄弟右孩子红 w->color = x->parent->color;x->parent->color = BLACK;if (w->right) w->right->color = BLACK;left_rotate(t, x->parent);x = t->root; // 终止循环 }} else {// 对称处理右侧情况 RBNode *w = x->parent->left;if (w->color == RED) {// Case 1镜像 w->color = BLACK;x->parent->color = RED;right_rotate(t, x->parent);w = x->parent->left;}if ((w->right == NULL || w->right->color == BLACK) &&(w->left == NULL || w->left->color == BLACK)) {// Case 2镜像 w->color = RED;x = x->parent;} else {if (w->left == NULL || w->left->color == BLACK) {// Case 3镜像 if (w->right) w->right->color = BLACK;w->color = RED;left_rotate(t, w);w = x->parent->left;}// Case 4镜像 w->color = x->parent->color;x->parent->color = BLACK;if (w->left) w->left->color = BLACK;right_rotate(t, x->parent);x = t->root;}}}if (x) x->color = BLACK;
}
// 公共删除接口
void rb_delete(RBTree *t, void *data) {RBNode *z = find_node(t, data);if (!z) return;RBNode *y = z, *x;Color original_color = y->color;if (!z->left) {x = z->right;transplant(t, z, z->right);} else if (!z->right) {x = z->left;transplant(t, z, z->left);} else {y = z->right;while (y->left) y = y->left;original_color = y->color;x = y->right;if (y->parent == z) {if (x) x->parent = y;} else {transplant(t, y, y->right);y->right = z->right;y->right->parent = y;}transplant(t, z, y);y->left = z->left;y->left->parent = y;y->color = z->color;}if (original_color == BLACK)delete_fixup(t, x);free(z);
}// 节点替换辅助函数
void transplant(RBTree *t, RBNode *u, RBNode *v) {if (!u->parent)t->root = v;else if (u == u->parent->left)u->parent->left = v;else u->parent->right = v;if (v)v->parent = u->parent;
}/* 遍历函数(与AVL树实现相同) */
void pre_order(RBNode *root, void (*callback)(void*)) {if (root) {callback(root->data);pre_order(root->left, callback);pre_order(root->right, callback);}
}
//递归形式实现的销毁树函数
/* 递归释放子树(内部函数)*/
static void _destroy_subtree(RBTree *t, RBNode *node) {if (!node) return;// 后序遍历释放子节点 _destroy_subtree(t, node->left);_destroy_subtree(t, node->right);// 释放数据内容 if (t->data_free) {t->data_free(node->data); // 用户自定义释放函数 }// 释放节点本身 free(node);
}/* 公开的销毁函数 */
void rb_destroy(RBTree *t) {if (!t) return;_destroy_subtree(t, t->root);t->root = NULL; // 重要!防止悬空指针 // 可选:重置比较函数指针 // t->compare = NULL;
}
//为避免栈溢出,迭代式实现
/* 内部节点释放函数 */
static void _free_node(RBTree *t, RBNode *node) {if (!node) return;// 解除节点间的关联 node->left = node->right = node->parent = NULL;// 释放数据内容 if (t->data_free) {t->data_free(node->data);}// 释放节点内存 free(node);
}/* 改进后的迭代销毁实现 */
void rb_destroy(RBTree *t) {if (!t || !t->root) return;RBNode *current = t->root;while (current) {if (!current->left) {// 无左子树,直接处理右子树 RBNode *right = current->right;_free_node(t, current);current = right;} else {// 找到左子树的最右节点 RBNode *pre = current->left;while (pre->right && pre->right != current) {pre = pre->right;}if (!pre->right) {// 建立临时链接用于回溯 pre->right = current;current = current->left;} else {// 断开临时链接并处理节点 pre->right = NULL;RBNode *temp = current;current = current->right;_free_node(t, temp);}}}t->root = NULL;
}
/* 示例使用 */
#include<stdio.h>
int int_compare(const void* a, const void* b) {return *(int*)a - *(int*)b;
}void print_int(void* data) {printf("%d ", *(int*)data);
}int main() {RBTree tree = {NULL, int_compare,free};// 插入测试 int nums[] = {7, 3, 18, 10, 22, 8, 11, 26};for (int i = 0; i < sizeof(nums)/sizeof(nums[0]); i++) {int* data = malloc(sizeof(int));*data = nums[i];rb_insert(&tree, data);}printf("Pre-order traversal:\n");pre_order(tree.root, print_int); // 输出:10 7 3 8 22 18 11 26 printf("\n");// 删除测试 int to_delete = 18;rb_delete(&tree, &to_delete);printf("\nAfter deletion of 18:\n");pre_order(tree.root, print_int); // 输出:10 7 3 8 22 11 26 printf("\n");rb_destroy(tree);return 0;
}
相关文章:
基本数据结构--平衡二叉搜索树之红黑树示例代码
红黑树的规则。红黑树的每个节点有颜色(红或黑),满足以下性质: 每个节点是红或黑。根节点是黑的。叶子节点(NIL节点)是黑的。红节点的子节点必须是黑的。从任一节点到其所有后代叶子节点的路径包含相同数量…...
GB/T 43698-2024 《网络安全技术 软件供应链安全要求》标准解读
一、43698-2024标准图解 https://mmbiz.qpic.cn/sz_mmbiz_png/rwcfRwCticvgeBPR8TWIPywUP8nGp4IMFwwrxAHMZ9Enfp3wibNxnfichT5zs7rh2FxTZWMxz0je9TZSqQ0lNZ7lQ/640?wx_fmtpng&fromappmsg 标准在线预览: 国家标准|GB/T 43698-2024 相关标准: &a…...
Python内置函数map(), list(), len(), iter(), hex(), hash()的详细解析,包括功能、语法、示例及注意事项
1. map(function, iterable, ...) 功能:对可迭代对象中的每个元素应用指定函数,返回一个迭代器。 参数: function:要执行的函数(可以是lambda表达式)。 iterable:一个或多个可迭代对象&#x…...
CF 278A.Circle Line
题目分析 输入n个数据作为路径,求从a到b的最短距离,需要将其相成一个圆圈,既可以从小往大走又可以从大往小走 思路分析 依然将数据存为数组,通过下标进行操作,既然说了有两种方式那就计算两种方式哪个更快就输出谁 代…...
DeepSeek模型构建与训练
在完成数据预处理之后,下一步就是构建和训练深度学习模型。DeepSeek提供了简洁而强大的API,使得模型构建和训练变得非常直观。无论是简单的全连接网络,还是复杂的卷积神经网络(CNN)或循环神经网络(RNN),DeepSeek都能轻松应对。本文将带你一步步构建一个深度学习模型,并…...
本地部署deepseek简单教程
部署deepseek,首先需要知道deepseek官网地址:DeepSeek 第一步:Ollama 去ollama下载对应的版本,我的电脑是window 在这里可以看到关于deepseek相关 第二步,下载完ollama无脑下一步就可以 这样属于安装成功 第三步&…...
3.1 可视化算子编程语言
HuggingFists的VO编程语言与常见的其它编程语言有一定的区别。其语言由两种不同的语法特征构成。一部分以可视化算子作为语法基础(简称:VO-O),辅助使用者可视化的完成数据处理/分析流程的编写;一部分采用表达式语法(简称:VO-E)&am…...
UnityShader学习笔记——多种光源
——内容源自唐老狮的shader课程 目录 1.光源类型 2.判断光源类型 2.1.在哪判断 2.2.如何判断 3.光照衰减 3.1.基本概念 3.2.unity中的光照衰减 3.3.光源空间变换矩阵 4.点光源衰减计算 5.聚光灯衰减计算 5.1.聚光灯的cookie(灯光遮罩) 5.2.聚…...
电脑右下角小喇叭没反应怎么回事,快速解决方案
当电脑右下角的小喇叭(音量图标)没有反应时,可以尝试以下快速解决方案: 一、基础检查与操作 检查键盘音量键: 按下键盘上的音量增加或减少键,或尝试Fn音量键(部分笔记本需组合键)&a…...
chrome-base 如何实现一个BindOnce
考虑一个问题: worker_thread.task_runner()->PostDelayedTask(FROM_HERE, base::BindOnce(&Ref::Foo, ref, 1), base::Milliseconds(1000)); BindOnce 是如何实现的呢? 翻看源码:base\functional\bind.h 写的 非常简洁 // Bind a…...
HTML学习之CSS三种引入方式
HTML学习之CSS三种引入方式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>…...
Mysql基于binlog主从同步配置
主配置: 修改配置文件:/etc/my.cnf 添加server-id1 重启MySQL服务:systemctl restart mysqld 创建用户并授权: mysql> create user rep192.168.79.% identified with mysql_native_password by 123456; Query OK, 0 rows aff…...
Docker Desktop安装到其他盘
Docker Desktop 默认安装到c盘,占用空间太大了,想给安装到其他盘,网上找了半天的都不对 正确安装命令: start /w "" "Docker Desktop Installer.exe" install --installation-dirF:\docker命令执行成功&am…...
NetCore Consul动态伸缩+Ocelot 网关 缓存 自定义缓存 + 限流、熔断、超时 等服务治理
网关 OcelotGeteway 网关 Ocelot配置文件 {//单地址多实例负载均衡Consul 实现动态伸缩"Routes": [{// 上游 》》 接受的请求//上游请求方法,可以设置特定的 HTTP 方法列表或设置空列表以允许其中任何方法"UpstreamHttpMethod": [ "Get", &quo…...
ubuntu 本地部署deepseek r1 蒸馏模型
本文中的文件路径或网络代理需要根据自身环境自行删改 一、交互式chat页面 1.1 open-webui 交互窗口部署:基于docker安装,且支持联网搜索 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台,旨在完全离线操作。它支持各种 LLM…...
go语言中的反射
为什么会引入反射 有时我们需要写一个函数,这个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在,这个时候我们就可以用到反射。 空接口可…...
旅行社项目展示微信小程序功能模块和开发流程
旅行社当前旅游线路的程序(微信小程序),旨在帮助旅行社更高效地管理线下活动预订,同时为客户提供便捷的报名和查看功能。适用于短途游、团队建设等活动,支持在线预订、缴费及订单管理,可根据用户需求定制更多个性化服务,为公司提升品牌知名度与客户体验。通过简洁明了的…...
JUC学习笔记02
文章目录 JUC笔记2练习题:手写线程池代码解释:AdvancedThreadPool 类:WorkerThread 内部类:AdvancedThreadPoolExample 类: 线程池的思考CPU密集型IO密集型 练习题:手写自动重试机练习题:手写定…...
【论文翻译】DeepSeek-V3论文翻译——DeepSeek-V3 Technical Report——第一部分:引言与模型架构
论文原文链接:DeepSeek-V3/DeepSeek_V3.pdf at main deepseek-ai/DeepSeek-V3 GitHub 特别声明,本文不做任何商业用途,仅作为个人学习相关论文的翻译记录。本文对原文内容直译,一切以论文原文内容为准,对原文作者表示…...
python编程-类结构,lambda语法,原始字符串
一个类的基本结构包括以下部分: 类名:用来描述具有相同属性和方法的对象的集合。 属性:类变量或实例变量,用于处理类及其实例对象的相关数据。 方法:在类中定义的函数,用于执行特定操作。 构造器ÿ…...
C++:代码常见规范1
头文件包含 (1)先系统头文件,后用户头文件:这是一个良好的编程习惯。系统头文件通常包含标准库的定义,而用户头文件则包含项目特定的定义。将系统头文件放在前面可以避免因用户头文件中的定义与系统头文件冲突而导致的问题。 #include <…...
C++(进阶五)--STL--用一颗红黑树封装map和set
目录 1.红黑树源码(简略版) 2.模板参数的控制 3.红黑树的结点 4.迭代器的实现 正向迭代器 反向迭代器 5.set的模拟实现 6.map的模拟实现 7.封装完成后的代码 RBTree.h mymap.h myset.h 1.红黑树源码(简略版) 下面我们…...
DeepSeek服务器繁忙问题的原因分析与解决方案
一、引言 随着人工智能技术的飞速发展,DeepSeek 等语言模型在众多领域得到了广泛应用。然而,在春节这段时间的使用过程中,用户常常遭遇服务器繁忙的问题,这不仅影响了用户的使用体验,也在一定程度上限制了模型的推广和…...
《手札·开源篇》数字化转型助力永磁电机企业降本增效:快速设计软件如何让研发效率提升40%?
数字化转型助力永磁电机企业降本增效:快速设计软件如何让研发效率提升40%? 一、痛点:传统研发模式正在吃掉企业的利润 永磁电机行业面临两大挑战: 研发周期长:一款新电机从设计到量产需6-12个月,电磁计算…...
飞算JavaAI :AI + 时代下的行业趋势引领者与推动者
在科技飞速发展的当下,AI 时代正以前所未有的速度重塑着各个行业的格局,而软件开发领域更是这场变革的前沿阵地。在众多创新力量之中,飞算JavaAI 脱颖而出,宛如一颗璀璨的新星,凭借其独树一帜的特性与强大功能&#x…...
【重新认识C语言----结构体篇】
目录 -----------------------------------------begin------------------------------------- 引言 1. 结构体的基本概念 1.1 为什么需要结构体? 1.2 结构体的定义 2. 结构体变量的声明与初始化 2.1 声明结构体变量 2.2 初始化结构体变量 3. 结构体成员的访…...
解决错误:CondaHTTPError: HTTP 000 CONNECTION FAILED for url
解决错误:CondaHTTPError: HTTP 000 CONNECTION FAILED for url 查看channels:vim ~/.condarcshow_channel_urls: true channels:- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/- http://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/…...
使用令牌桶算法通过redis实现限流
令牌桶算法是一种常用的限流算法,它可以平滑地控制请求的处理速率。在 Java 中结合 Redis 实现令牌桶算法,可以利用 Redis 的原子操作来保证多节点环境下的限流效果。 一 实现思路 初始化令牌桶:在 Redis 中存储令牌桶的相关信息࿰…...
Docker的进程和Cgroup概念
Docker的进程和Cgroup概念 容器里的进程组织或关系0号进程:containerd-shim1号进程:容器内的第一个进程进程收到信号后的三种反应两个特权信号在容器内执行 kill 命令的行为 Cgroup 介绍CPU Cgroup 中与 CFS 相关的参数Kubernetes 中的资源管理memory cg…...
Day68:类的多态
在面向对象编程(OOP)中,多态(Polymorphism)是指不同类的对象对同一消息作出响应的能力。换句话说,多态允许不同类的对象使用相同的方法名,但实现不同的行为。多态是通过继承和方法重写来实现的,通常可以分为方法重写和接口重载。 在 Python 中,多态常常通过方法重写来…...
