红黑树的应用:
  1. 利用key_value对,快速查找,O(logn)
    1. socket与客户端id之间,形成映射关系(socket, id)
    2. 内存分配管理
      1. 一整块内存,不断分配小块
      2. 每分配一次,就加入到红黑树
      3. 释放的时候,在红黑树找到相应的块,然后去释放
  2. 利用红黑树中序遍历是顺序的特性
    1. 进程的调度
      1. 进程处于等待状态,每个进程都有等待的时间,在未来某个时刻会运行,将这些进程利用红黑树组织起来
      2. 在某个时刻,找到对应时刻的节点,然后中序遍历,就可以把该节点之前的节点全部运行到。
  3. nginx定时器
 
为什么使用红黑树不使用哈希表?
  • 极少情况下,需要key是有序的,如定时器
 
二叉排序树(bstree)
  1. 左子树 < 根 < 右子树
  2. 中序遍历结果是顺序的
  3. 极端情况下,如果顺序插入,结果就成了链表
    1. 为了解决这个问题,引入了红黑树
 
红黑树性质
  1. 每个节点是红色的或黑色的
  2. 根节点是黑色的
  3. 叶子节点是黑色的
  4. 红色节点的两个子节点必须是黑色的
  5. 对每个节点,该节点到其子孙节点的所有路径上的包含相同数目的黑节点(黑高相同)
    1. 最短路径就是全黑
    2. 最长路径就是黑红相间
 
如何证明红黑树的正确性?
  • 采用归纳法
 
左旋与右旋
  • 改变三个方向,六根指针
 
红黑树的插入:
  1. 插入节点的时候,原先的树是满足红黑树性质的
  2. 插入节点的颜色是红色更容易满足红黑树的性质
  3. 插入的节点是红色,且其父节点也是红色的时候,需要调整
 
插入有三种情况:
  1. 叔父节点是红色
  2. 叔父节点是黑色,且祖父节点,父节点和插入节点不是一条直线
  3. 叔父节点是黑色,且祖父节点,父节点和插入节点是一条直线
 
  • 平衡二叉树:
    • 内部不是color,而是一个high记录高度,如果左右子树高度相差超过1,就需要调整。
 
红黑树的删除:
  1. 什么是删除节点? y-> y是z的后继节点
  2. 什么是轴心节点? x是y的右子树
    1. 如果x是红色,把x变成黑色
    2. 如果x是黑色,需要进行调整
 
删除y节点,是什么颜色的时候需要调整?
  • 黑色需要调整,删除黑色破坏了黑高
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #define RED 1
#define BLACK 2 typedef int KEY_TYPE; 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; rbtree_node *rbtree_mini(rbtree *T, rbtree_node *x) {
while (x->left != T->nil) {
x = x->left;
}
return x;
} rbtree_node *rbtree_maxi(rbtree *T, rbtree_node *x) {
while (x->right != T->nil) {
x = x->right;
}
return x;
} rbtree_node *rbtree_successor(rbtree *T, rbtree_node *x) {
rbtree_node *y = x->parent; if (x->right != T->nil) {
return rbtree_mini(T, x->right);
} while ((y != T->nil) && (x == y->right)) {
x = y;
y = y->parent;
}
return y;
} void rbtree_left_rotate(rbtree *T, rbtree_node *x) { rbtree_node *y = x->right; // x --> y , y --> x, right --> left, left --> right x->right = y->left; //1 1
if (y->left != T->nil) { //1 2
y->left->parent = x;
} y->parent = x->parent; //1 3
if (x->parent == T->nil) { //1 4
T->root = y;
} else if (x == x->parent->left) {
x->parent->left = y;
} else {
x->parent->right = y;
} y->left = x; //1 5
x->parent = y; //1 6
} void rbtree_right_rotate(rbtree *T, rbtree_node *y) { rbtree_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) {
T->root = x;
} else if (y == y->parent->right) {
y->parent->right = x;
} else {
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
if (z->parent == z->parent->parent->left) {
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 { if (z == z->parent->right) {
z = z->parent;
rbtree_left_rotate(T, z);
} z->parent->color = BLACK;
z->parent->parent->color = RED;
rbtree_right_rotate(T, z->parent->parent);
}
}else {
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) {
z = z->parent;
rbtree_right_rotate(T, z);
} 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; while (x != T->nil) {
y = x;
if (z->key < x->key) {
x = x->left;
} else if (z->key > x->key) {
x = x->right;
} else { //Exist
return ;
}
} 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);
} void rbtree_delete_fixup(rbtree *T, rbtree_node *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->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) { rbtree_node *y = T->nil;
rbtree_node *x = T->nil; if ((z->left == T->nil) || (z->right == T->nil)) {
y = z;
} else {
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);
}
} int main() { int keyArray[20] = {24,25,13,35,23, 26,67,47,38,98, 20,19,17,49,12, 21,9,18,14,15}; rbtree *T = (rbtree *)malloc(sizeof(rbtree));
if (T == NULL) {
printf("malloc failed\n");
return -1;
} T->nil = (rbtree_node*)malloc(sizeof(rbtree_node));
T->nil->color = BLACK;
T->root = T->nil; rbtree_node *node = T->nil;
int i = 0;
for (i = 0;i < 20;i ++) {
node = (rbtree_node*)malloc(sizeof(rbtree_node));
node->key = keyArray[i];
node->value = NULL; rbtree_insert(T, node); } rbtree_traversal(T, T->root);
printf("----------------------------------------\n"); for (i = 0;i < 20;i ++) { rbtree_node *node = rbtree_search(T, keyArray[i]);
rbtree_node *cur = rbtree_delete(T, node);
free(cur); rbtree_traversal(T, T->root);
printf("----------------------------------------\n");
} }

C++实现红黑树的更多相关文章

  1. 红黑树——算法导论(15)

    1. 什么是红黑树 (1) 简介     上一篇我们介绍了基本动态集合操作时间复杂度均为O(h)的二叉搜索树.但遗憾的是,只有当二叉搜索树高度较低时,这些集合操作才会较快:即当树的高度较高(甚至一种极 ...

  2. jdk源码分析红黑树——插入篇

    红黑树是自平衡的排序树,自平衡的优点是减少遍历的节点,所以效率会高.如果是非平衡的二叉树,当顺序或逆序插入的时候,查找动作很可能会遍历n个节点 红黑树的规则很容易理解,但是维护这个规则难. 一.规则 ...

  3. 谈c++ pb_ds库(二) 红黑树大法好

    厉害了,没想到翻翻pb_ds库看到这么多好东西,封装好的.现成的splay.红黑树.avl... 即使不能在考场上使用也可以用来对拍哦 声明/头文件 #include <ext/pb_ds/tr ...

  4. 定时器管理:nginx的红黑树和libevent的堆

    libevent 发生超时后, while循环一次从堆顶del timer——直到最新调整的最小堆顶不是超时事件为止,(实际是del event),但是会稍后把这个timeout的 event放到ac ...

  5. 从2-3-4树到红黑树(下) Java与C的实现

    欢迎探讨,如有错误敬请指正 如需转载,请注明出处   http://www.cnblogs.com/nullzx/ 相关博客: 从2-3-4树到红黑树(上) 从2-3-4树到红黑树(中) 1. 实现技 ...

  6. 红黑树/B+树/AVL树

    RB Tree 红黑树  :http://blog.csdn.net/very_2/article/details/5722682 Nginx的RBTree实现   :http://blog.csdn ...

  7. 论AVL树与红黑树

    首先讲解一下AVL树: 例如,我们要输入这样一串数字,10,9,8,7,15,20这样一串数字来建立AVL树 1,首先输入10,得到一个根结点10 2,然后输入9, 得到10这个根结点一个左孩子结点9 ...

  8. DataStructure——红黑树学习笔记

    1.前言 本文伪码和解释参考: http://blog.csdn.net/v_JULY_v/article/details/6105630 C实现的源码本文未贴出,请见: http://blog.cs ...

  9. 红黑树(Red-Black tree)

    红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性.同时红黑树更是一颗自平衡的排序二叉树.我们知道一颗基本的二叉树他们都需要满足一个基本性质–即树中的任何节点的值大于它的左子节点,且小 ...

  10. map,hash_map, hash_table, 红黑树 的原理和使用

    在刷算法题的时候总是碰到好多题,号称可以用hash table来解题.然后就蒙圈了. 1.首先,map和hash_map的区别和使用: (1)map底层用红黑树实现,hash_map底层用hash_t ...

随机推荐

  1. AES加密基本原理图解

    AES加密 Fright-Moch整理 AES简介 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的).对 ...

  2. 论文解读(BYOL)《Bootstrap Your Own Latent A New Approach to Self-Supervised Learning》

    论文标题:Bootstrap Your Own Latent A New Approach to Self-Supervised Learning 论文方向:图像领域 论文来源:NIPS2020 论文 ...

  3. webpack learn1-初始化项目1

    使用Visual  Studio Code软件使用准备,先安装一些插件,加快开发效率(还有Language Packs 选择简体中文安装后重启软件,可切换为中文): 下面是项目初始化步骤: 1 软件打 ...

  4. Dapr实战(三)状态管理

    状态管理解决了什么 分布式应用程序中的状态可能很有挑战性. 例如: 应用程序可能需要不同类型的数据存储. 访问和更新数据可能需要不同的一致性级别. 多个用户可以同时更新数据,这需要解决冲突. 服务必须 ...

  5. win10系统移动热点使用技巧

    win10系统是自动移动热点功能,在平时测试的时候,有时需要进行手机抓包,需要手机和电脑处于同一网络当中,这时可以开启热点使用. 如何开启移动热点? 直接搜索"移动热点" 但是如果 ...

  6. P6177-Count on a tree II/[模板]树分块

    正题 题目链接:https://www.luogu.com.cn/problem/P6177 题目大意 \(n\)个点的一棵树\(m\)次询问树上颜色. 强制在线 \(1\leq n\leq 4\ti ...

  7. Redis新旧复制

    在Redis中,用户可以通过执行SALVEOF命令,让一个服务器去复制另一个服务器. 127.0.0.1:12345> SLAVEOF 127.0.0.1 6379 OK 6379的奴隶是123 ...

  8. 【原创】SystemVerilog中的typedef前置声明方式

    SystemVerilog中,为了是代码简洁.易记,允许用户根据个人需要使用typedef自定义数据类型名,常用的使用方法可参见"define和typedef区别".但是在Syst ...

  9. Shiro 550反序列化漏洞分析

    Shiro 550反序列化漏洞分析 一.漏洞简介 影响版本:Apache Shiro < 1.2.4 特征判断:返回包中包含rememberMe=deleteMe字段. Apache Shiro ...

  10. Python标准库模块之heapq – 堆构造

    Python标准库模块之heapq – 堆构造 读前福利:几百本经典书籍https://www.johngo689.com/2158/ 原文链接:https://www.johngo689.com/2 ...