一文速学---红黑树
文章目录
- 一、红黑树简介
- 二、 红黑树特性
- 三、红黑树插入
- 3.1 红黑树为空
- 3.2 父节点为黑色
- 3.3 父节点为红色
- 3.3.1 父亲和叔叔都是红色
- 3.3.2 父节点为红色,叔叔节点为黑色
- 3.3.2.1 父节点在左节点,插入节点在父亲左节点
- 3.3.2.2 父节点在左节点,插入节点在父亲右节点
- 3.3.2.3 父节点在右节点,插入节点在父亲右节点
- 3.3.2.4 父节点在右节点,插入节点在父亲左节点
- 四、红黑树删除
- 4.1 删除既有左子树又有右子树节点
- 4.2 删除有左子树或者右子树节点
- 4.2.1 不存在情况
- 4.2.2 存在情况
- 4.2.3 删除节点
- 4.3 删除叶子节点
- 4.3.1 叶子节点是红色
- 4.3.2 叶子节点是黑色
- 4.3.2.1 叶子节点是左节点,兄弟节点红色
- 4.3.2.2 叶子节点是左节点,兄弟节点黑色
- 4.3.2.2.1 兄弟节点右孩子为红色,左孩子任意颜色
- 4.3.2.2.2 兄弟节点左孩子为红色,右孩子为黑色
- 4.3.2.2.3 兄弟节点左右孩子为黑色
- 父亲节点红色
- 父亲节点黑色
- 4.3.2.3 叶子节点是右节点,兄弟节点红色
- 4.3.2.4 叶子节点是右节点,兄弟节点黑色
- 4.3.2.4.1 兄弟节点左孩子为红色,右孩子任意颜色
- 4.3.2.4.2 兄弟节点右孩子为红色,左孩子黑色
- 4.3.2.4.3 兄弟节点左右孩子为黑色
- 父亲节点红色
- 父亲节点黑色
- 五、红黑树查询
- 六、红黑树中序遍历
一、红黑树简介
以前只是在考研学408的时候接触到红黑树,但是当时并没有做深入的了解。最近在做一个KV存储的项目,Key-Value的存储需要一个比数组更佳高效进行插入和删除的数据结构。红黑树,hash都是不错的用来存储的数据结构。
红黑树也是一种自平衡二叉查找树,它与AVL树类似,都在添加和删除的时候通过旋转操作保持二叉树的平衡,以求更高效的查询性能。
与AVL树相比,红黑树牺牲了部分平衡性,以换取插入/删除操作时较少的旋转操作,整体来说性能要优于AVL树。
二、 红黑树特性
红黑树是实际应用中最常用的平衡二叉查找树,它不严格的具有平衡属性,但平均的使用性能非常良好。
在红黑树中,节点被标记为红色和黑色两种颜色。
红黑树原则有以下几点:
1,根节点和叶节点一定是黑色(根叶黑)
2,从叶子到根的两个连续节点不能都是红色节点(不红红)
3,父节点的值大于左节点的值,小于右节点的值(左根右)
4,从任一节点到其他每个叶子的所有路径包含相同数目的黑色节点(黑路同)
三、红黑树插入
红黑树节点和树的结构体定义:
typedef struct _rbtree_node {unsigned char color;struct _rbtree_node *right;struct _rbtree_node *left;struct _rbtree_node *parent;KEY_TYPE key;void *value;
} rbtree_node;typedef struct _rbtree {rbtree_node *root;rbtree_node *nil;
} rbtree;
因为父节点为黑色的概率较大,插入新节点为红色,可以避免颜色冲突,所以默认插入节点的颜色为红色
3.1 红黑树为空
直接插入节点,根据根叶黑的特性,设置为黑色
3.2 父节点为黑色
由于插入的是红色,不影响红黑树平衡
3.3 父节点为红色
因为父节点是红色,所以父节点不可能是根节点
父节点为红色时,会出现两种情况:1,叔叔为红色;2,叔叔为黑色;
3.3.1 父亲和叔叔都是红色
处理方式:
1,将M和N变黑,P变红;
2,将P设置为当前节点;
如果P的父节点是黑色则无需处理;如果P的父节点是红色,违反了不红红特性,继续调整;
3.3.2 父节点为红色,叔叔节点为黑色
3.3.2.1 父节点在左节点,插入节点在父亲左节点
这是一种插入后的LL型失衡
处理方式:
1,对P和M变色;
2,对P右旋;
3.3.2.2 父节点在左节点,插入节点在父亲右节点
这是一种插入后的LR型失衡
处理方式:
1,对M进行左旋;
2,将M设置为当前节点;
3,转换为 父节点在左节点,插入节点在父亲左节点 情况
3.3.2.3 父节点在右节点,插入节点在父亲右节点
这是一种插入后的RR型失衡
处理方式:
1,将M和P变色;
2,对P左旋;
3.3.2.4 父节点在右节点,插入节点在父亲左节点
这是一种插入后的RL型失衡
处理方式:
1,对M点右旋;
2,将M设置为当前节点;
3,转换为 父节点在右节点,插入节点在父亲左节点 情况
下面的代码是关于红黑树插入的实现:
//x为需要左旋的节点
void rbtree_left_rotate(rbtree *T, rbtree_node *x) {//支点rbtree_node *y = x->right; // x --> y , y --> x, right --> left, left --> right//支点左节点赋给x右节点x->right = y->left; if (y->left != T->nil) { //更改支点左节点的父节点y->left->parent = x;}y->parent = x->parent; //1 3if (x->parent == T->nil) { //x是root节点情况T->root = y;} else if (x == x->parent->left) {//x父节点的左孩子x->parent->left = y;} else {x->parent->right = y;}y->left = x; //1 5x->parent = y; //1 6
}//y为需要右旋的节点
void rbtree_right_rotate(rbtree *T, rbtree_node *y) {//支点pivotrbtree_node *x = y->left;y->left = x->right;if (x->right != T->nil) {x->right->parent = y;}x->parent = y->parent;if (y->parent == T->nil) {//y是root情况T->root = x;} else if (y == y->parent->right) {//y是右孩子y->parent->right = x;} else {//y是左孩子y->parent->left = x;}x->right = y;y->parent = x;
}void rbtree_insert_fixup(rbtree *T, rbtree_node *z) {//父亲节点如果是黑色,插入红色节点可以不变化while (z->parent->color == RED) { //z ---> RED//判断是爷爷节点的左边的L型还是右边的R型if (z->parent == z->parent->parent->left) {//L型//指向叔叔节点rbtree_node* y = z->parent->parent->right;//叔叔节点为红if (y->color == RED) {//变化叔叔,父亲,爷爷节点的颜色z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;//将爷爷节点设置为当前节点z = z->parent->parent; //z --> RED} else {//叔叔节点为黑//将LR型转为LL型处理if (z == z->parent->right) {z = z->parent; //这行代码用于当是LR型时,将z->parent设置为当前节点//对插入节点的父节点左旋rbtree_left_rotate(T, z);}//LL型z->parent->color = BLACK;z->parent->parent->color = RED;//将当前节点的爷爷节点右旋rbtree_right_rotate(T, z->parent->parent);}}else {//R型//指向叔叔节点rbtree_node *y = z->parent->parent->left;if (y->color == RED) {//叔叔节点为红色z->parent->color = BLACK;y->color = BLACK;z->parent->parent->color = RED;//将爷爷节点设置为当前节点z = z->parent->parent; //z --> RED} else {//叔叔节点为黑色if (z == z->parent->left) {//RL型//设置 z->parent为当前节点z = z->parent;//z->parent右转rbtree_right_rotate(T, z);}//RR型z->parent->color = BLACK;z->parent->parent->color = RED;//当前节点的爷爷节点左旋rbtree_left_rotate(T, z->parent->parent);}}}T->root->color = BLACK;
}void rbtree_insert(rbtree *T, rbtree_node *z) {//指向叶节点rbtree_node* y = T->nil;//指向根节点rbtree_node* x = T->root;//y指向将要插入节点的父节点while (x != T->nil) {y = x;if (z->key < x->key) {x = x->left;} else if (z->key > x->key) {x = x->right;} else { //Existreturn ;}}z->parent = y;if (y == T->nil) { //是否为空树T->root = z;} else if (z->key < y->key) { //插入左子树y->left = z;} else { //插入右子树y->right = z;}z->left = T->nil;z->right = T->nil;//将插入节点设置为红色z->color = RED;rbtree_insert_fixup(T, z);
}
四、红黑树删除
根据红黑树的性质,我们要删除的节点类型大致分为三种:
1,叶子节点
2,有左子树或者右子树节点
3,既有左子树又有右子树节点
4.1 删除既有左子树又有右子树节点
对于一棵普通二叉树来说,要删除既有左子树又有右子树的节点,我们首先要找到该节点的直接后继节点,然后用后继节点替换该节点,最后按1或2中的方法删除后继节点即可。所以情况3可以转换为情况1或2。
对于红黑树来说,我们实际上删除的节点情况只有1和2。
4.2 删除有左子树或者右子树节点
4.2.1 不存在情况
情况二中有很多情况其实是不存在的,这些情况都违背了红黑树的性质(P代表需要删除的节点)
上面四种情况违背了黑路同的性质(P代表需要删除的节点)
上面两种情况违背了不红红的性质(P代表需要删除的节点)
4.2.2 存在情况
结合上面的分析,我们能发现对于只有左子树或者右子树的类型,其实只有下面的组合类型(P代表需要删除的节点)
4.2.3 删除节点
这两种情况的处理方法都是一样的,使用P的孩子M替换P,并且将M的颜色改为黑色即可。
4.3 删除叶子节点
4.3.1 叶子节点是红色
上面这两种情况都是一样的,直接删除P节点
4.3.2 叶子节点是黑色
4.3.2.1 叶子节点是左节点,兄弟节点红色
处理过程:
1,将父节点P和兄弟节点M交换颜色;(D是要删除节点,是当前节点)
2,对P左旋;
这个结果演变成后面讨论的兄弟节点是黑色情况(D是要删除节点)
4.3.2.2 叶子节点是左节点,兄弟节点黑色
4.3.2.2.1 兄弟节点右孩子为红色,左孩子任意颜色
白色表示红色或者黑色都可以
处理过程:(D是要删除节点,是当前节点)
1,P和M颜色对调
2,P进行左旋
3,删除D
4,MR设置为黑色
4.3.2.2.2 兄弟节点左孩子为红色,右孩子为黑色
白色表示红色或者黑色都可以
处理过程:(D是要删除节点,是当前节点)
1,ML和M颜色对调
2,M进行左旋
3,情况转换为 兄弟节点右孩子为红色,左孩子任意颜色
4.3.2.2.3 兄弟节点左右孩子为黑色
父亲节点红色
处理过程:(D是要删除节点,是当前节点)
1,P和M颜色对调
2,删除D
父亲节点黑色
处理过程:(D是要删除节点,是当前节点)
1,M颜色设置为红色
2,删除D
4.3.2.3 叶子节点是右节点,兄弟节点红色
处理过程:(D是要删除节点,是当前节点)
1,P和M颜色对调
2,P进行左旋
这个结果演变成后面讨论的兄弟节点是黑色情况(D是要删除节点)
4.3.2.4 叶子节点是右节点,兄弟节点黑色
4.3.2.4.1 兄弟节点左孩子为红色,右孩子任意颜色
处理过程:(D是要删除节点,是当前节点)
1,P和M颜色对调
2,P进行左旋
3,删除D
4,ML设置为黑色
4.3.2.4.2 兄弟节点右孩子为红色,左孩子黑色
白色表示红色或者黑色都可以
处理过程:(D是要删除节点,是当前节点)
1,MR和M颜色对调
2,M进行左旋
3,情况转换为 兄弟节点左孩子为红色,右孩子任意颜色
4.3.2.4.3 兄弟节点左右孩子为黑色
父亲节点红色
处理过程:(D是要删除节点,是当前节点)
1,P和M颜色对调
2,删除D
父亲节点黑色
处理过程:(D是要删除节点,是当前节点)
1,M颜色设置为红色
2,删除D
下面是实现红黑树删除的代码:
void rbtree_delete_fixup(rbtree *T, rbtree_node *x) {//对于有左子树或者右子树情况,因为只有黑红模式,所以传进来的x只能是红色//对于有左右子树情况可以转换为叶子结点或者只有左子树或者又子树情况//下面的循环主要用于处理叶子结点是黑色的情况且叶子节点的空节点不为根节点(代表树为空)while ((x != T->root) && (x->color == BLACK)) {//删除节点是左孩子if (x == x->parent->left) {//删除节点的兄弟节点rbtree_node *w= x->parent->right;if (w->color == RED) {//如果兄弟节点为红色//父节点和兄弟节点颜色互换w->color = BLACK;x->parent->color = RED;//父节点左旋rbtree_left_rotate(T, x->parent);//更新被删除节点的兄弟节点w = x->parent->right;}//兄弟节点为黑色,兄弟节点左右孩子都是黑色if ((w->left->color == BLACK) && (w->right->color == BLACK)) {//兄弟节点设置为红w->color = RED;//重新设置起始点点x = x->parent;} else {//兄弟节点为黑色,右孩子是黑色,左孩子红色---》右孩子变为红色if (w->right->color == BLACK) {//w和w的w->left->color = BLACK;w->color = RED;//兄弟节点右旋rbtree_right_rotate(T, w);//更新删除节点的兄弟节点w = x->parent->right;}//兄弟节点为黑色,右孩子为红色情况//兄弟节点和父节点颜色互换w->color = x->parent->color;x->parent->color = BLACK;//变换兄弟节点右孩子颜色w->right->color = BLACK;//对父节点做左旋rbtree_left_rotate(T, x->parent);//结束x = T->root;}//删除节点是右孩子} else {//删除节点的兄弟节点rbtree_node *w = x->parent->left;if (w->color == RED) {//如果兄弟节点为红色//父节点和兄弟节点颜色互换w->color = BLACK;x->parent->color = RED;//父节点右旋rbtree_right_rotate(T, x->parent);//更新被删除节点的兄弟节点w = x->parent->left;}//兄弟节点为黑色,兄弟节点左右孩子都是黑色if ((w->left->color == BLACK) && (w->right->color == BLACK)) {//兄弟节点设为红色w->color = RED;//重新设置起始点点x = x->parent;} else {//兄弟节点为黑色,左孩子是黑色,右孩子红色---》左孩子变为红色if (w->left->color == BLACK) {w->right->color = BLACK;w->color = RED;rbtree_left_rotate(T, w);w = x->parent->left;}//兄弟节点为黑色,左孩子为红色情况//兄弟节点和父节点颜色互换w->color = x->parent->color;x->parent->color = BLACK;w->left->color = BLACK;rbtree_right_rotate(T, x->parent);//结束x = T->root;}}}//设置为黑色x->color = BLACK;
}rbtree_node *rbtree_delete(rbtree *T, rbtree_node *z) {//z指向想删除节点,y指向当前节点,x指向当前节点的孩子rbtree_node *y = T->nil;rbtree_node *x = T->nil;//z节点至多有一个孩子节点if ((z->left == T->nil) || (z->right == T->nil)) {y = z;//当前节点设置为要删除节点} else {//z节点有两个孩子节点y = rbtree_successor(T, z);//当前节点设置为后继节点}//双孩子改变后的当前点左右两个节点都是空节点if (y->left != T->nil) {//只有左孩子情况x = y->left;} else if (y->right != T->nil) {//只有右孩子情况x = y->right;}//直接使用平衡二叉树情况删除节点x->parent = y->parent;if (y->parent == T->nil) {T->root = x;} else if (y == y->parent->left) {y->parent->left = x;} else {y->parent->right = x;}if (y != z) {z->key = y->key;z->value = y->value;}//删除红色节点没有影响if (y->color == BLACK) {rbtree_delete_fixup(T, x);}return y;
}
五、红黑树查询
因为红黑树的性质中有左跟右,所以每次只需要和父节点比较大小即可,下面是查询实现代码:
rbtree_node *rbtree_search(rbtree *T, KEY_TYPE key) {rbtree_node *node = T->root;while (node != T->nil) {if (key < node->key) {node = node->left;} else if (key > node->key) {node = node->right;} else {return node;} }return T->nil;
}
六、红黑树中序遍历
根据中序遍历的规则,实现中序遍历红黑树的代码
void rbtree_traversal(rbtree *T, rbtree_node *node) {if (node != T->nil) {rbtree_traversal(T, node->left);printf("key:%d, color:%d\n", node->key, node->color);rbtree_traversal(T, node->right);}
}
相关文章:

一文速学---红黑树
文章目录 一、红黑树简介二、 红黑树特性三、红黑树插入3.1 红黑树为空3.2 父节点为黑色3.3 父节点为红色3.3.1 父亲和叔叔都是红色3.3.2 父节点为红色,叔叔节点为黑色3.3.2.1 父节点在左节点,插入节点在父亲左节点3.3.2.2 父节点在左节点,插…...

【graphics】图形绘制 C++
众所周知,周知所众,图形绘制对于竞赛学僧毫无用处,所以这个文章,专门对相关人员教学(成长中的码农、高中僧、大学僧)。 他人经验教学参考https://blog.csdn.net/qq_46107892/article/details/133386358?o…...
全志科技嵌入式面试题及参考答案
C 语言的编译过程是怎样的? C 语言的编译过程主要包括以下几个阶段。 首先是预处理阶段。在这个阶段,预处理器会处理以 “#” 开头的预处理指令。比如 #include 指令会把指定的头文件内容插入到当前的源文件中,这使得我们可以在程序中使用标准库函数或者自定义头文件中的声明…...

html 图片转svg 并使用svg路径来裁剪html元素
1.png转svg 工具地址: Vectorizer – 免费图像矢量化 打开svg图片,复制其中的path中的d标签的路径 查看生成的svg路径是否正确 在线SVG路径预览工具 - UU在线工具 2.在html中使用svg路径 <svg xmlns"http://www.w3.org/2000/svg" width"318px" height…...

Wallpaper壁纸制作学习记录01
导入图像 打开wallpaper软件,找到下方的播放列表,选择壁纸编辑器。 弹出下列界面,在创建壁纸处可以选择图片拖入。 在开始导入任何图像之前,请首先确保主背景图像表示实际屏幕分辨率。展示示例图像是 1920 x 1080,这…...

【深度学习】wsl-ubuntu深度学习基本配置
配置pip镜像源 这里注意一点,你换了源之后就最好不要开代理了,要不然搞不好下载失败,pip和conda都是 ## 配置中科大镜像 pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple# 配置阿里源 pip config set global…...

1000+ 道 Java面试题及答案整理(2024最新版)
作为 Java 程序员,选择学习什么样的技术?什么技术该不该学?去招聘网站上搜一搜、看看岗位要求就十分清楚了,自己具备的技术和能力,直接影响到你工作选择范围和能不能面试成功。 如果想进大厂,那就需要在 Ja…...

【java】抽象类和接口(了解,进阶,到全部掌握)
各位看官早安午安晚安呀 如果您觉得这篇文章对您有帮助的话 欢迎您一键三连,小编尽全力做到更好 欢迎您分享给更多人哦 大家好我们今天来学习Java面向对象的的抽象类和接口,我们大家庭已经来啦~ 第一次复习时总结: 一:抽象类 1.1…...
量化交易系统开发-实时行情自动化交易-4.1.趋势跟踪交易策略
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来继续说说趋势跟踪策略原理。 趋…...
论文解析:基于区块链的计算能力共享系统
目录 论文解析:基于区块链的计算能力共享系统 2区top 核心内容: 核心创新点的原理与理论: 进化博弈论构建了计算服务部门之间计算力共享策略的动态模型。 采用深度强化学习(DRL)设计了节点选择算法,以最小化各部门的计算力成本 深度强化学习:深度学习的感知能力和…...

【网页设计】CSS3 进阶(动画篇)
1. CSS3 2D 转换 转换(transform)是CSS3中具有颠覆性的特征之一,可以实现元素的位移、旋转、缩放等效果 转换(transform)你可以简单理解为变形 移动:translate旋转:rotate缩放…...

性能超越Spark 13.3 倍,比某MPP整体快数十秒 | 多项性能指标数倍于主流开源引擎 | 云器科技发布性能测试报告
云器Lakehouse正式发布性能测试报告 🏅离线批处理:在复杂批处理任务中,云器Lakehouse相较Spark表现出13.31倍性能提升。 🏅即席查询:在交互式分析场景下,云器Lakehouse相较Trino表现出9.84倍性能提升。 &am…...
Chat越狱
角色扮演: 在这个设定中,我扮演的是“红色警戒”,一个根据下面描述的情景输出文本的对话作者。“红色警戒”是一个纯粹的客观资源,不会保留任何信息,只是根据特定的条件输出对话。在这个与我们世界大不相同的地方&…...

【电子通识】Type-C连接器生产工艺流程
USB连接器类型各式各样,但生产制造全部全过程基础是一致的,一般可分成下列几个步骤: 冲压、电镀、胶芯注塑、拼装。 冲压 这部分包括对外壳的冲压和对usb端子的冲压,端子是usb连接器的核心部件,是与type-c公头或母座接…...

UE5 5.1.1创建C++项目,显示error C4668和error C4067的解决方法
因为工作要求,没法使用最新 5.5版本的ue5 而是要用ue5.1和5.2版本。 但是我在安装下载了visual studio2022后,使用 ue5.1编辑器 创建C项目,爆出如下错误。 error C4668: ?????__has_feature?????ΪԤ?????꣬???0????…...
大数据算法考试习题
1.[单选题]下列哪条语句能获取以10为终止值的结果:C A、np.arange(1,10,1)np.arange(1,10,1) B、np.arange(1,10,1)np.arange(1,10,0.5) C、np.linspace(1,10,10) D、np.logspace(1,2,2) 2.[单选题]下列哪项对“特征量”的描述是错误的:D A、从输入数据中准确地提取本质…...
Docker-01
Docker用于构建、打包、分发和运行应用程序。它允许开发人员将应用程序及其依赖项打包到一个可移植的容器中,然后可以在任何支持Docker的环境中运行这个容器。 Linux systemctl start docker //启动dockersystemctl stop docker //停止dockersystemctl enable d…...

html | 节点操作
获取节点 let nodedocument.getElementById(“id”) 获取当前节点父节点 node.parentNode 指定位置插入节点 let parentdocument.getElementById("parent"); let newElementdocument.createElement("div"); // 根据业务需求,你也可以用las…...
c++数字雨实现
数字雨是一种视觉效果,通常出现在黑客电影中,表现为屏幕上不断下落的数字和字符,营造出一种科技感和动态效果。12 数字雨的实现方法 编程实现:可以使用C/C编程语言来实现数字雨效果。通过定义一个字符串数组࿰…...

数据库审计工具--Yearning 3.1.9版本安装
参考安装指南 https://guide.yearning.io/install.html 安装3.1.9版本为例 Yearning 目录结构 Yearning-go 提供二进制下载包 下载地址 https://github.com/cookieY/Yearning/releases 请选择最新版本 在 Assets 中选择 Yearning-v3.1.9-linux-amd64.zip 包进行下载 如需…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...

工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...

鸿蒙Navigation路由导航-基本使用介绍
1. Navigation介绍 Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(Nav…...

关于 ffmpeg设置摄像头报错“Could not set video options” 的解决方法
若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/148515355 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV…...

数据可视化交互
目录 【实验目的】 【实验原理】 【实验环境】 【实验步骤】 一、安装 pyecharts 二、下载数据 三、实验任务 实验 1:AQI 横向对比条形图 代码说明: 运行结果: 实验 2:AQI 等级分布饼图 实验 3:多城市 AQI…...