• Day18:初识B、B+树&RB树


    一、B树和B+树

    1.B树:


        23树的基础上  引入  M值
        23树就是M值为3的B树

    Day13:数据结构之2-3树__https://blog.csdn.net/zjjaibc/article/details/126194415?spm=1001.2014.3001.5501

    2.B+树:


        B树加上两个特性
            1. 数据只存在叶子节点上
            2. 叶子节点之间用指针连接


            通常用于数据库操作系统文件系统中。B+树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+树元素自底向上插入,这与二叉树恰好相反。

            数据库  DB  DBA   关系型数据库  B+树
                MySql  

            硬盘:
                物理结构       (内存四区:代码区  栈区  堆区  静态区
                数据存储结构      B+树  

     查询的时候,

            相当于根据索引大致确定了查找的区间,所有的真实数据均放在叶子结点上,

            且相互连接构成了一个链表,.

    二、红黑树: 

    红黑二叉树:
        不怎么降低AVL的查找效率,大幅优化增删效率

    红黑二叉树 相对AVL树:
        稍稍降低查找效率(不是绝对平衡) 增删效率加快很多(三次旋转搞定)

    红黑二叉树规则:
        1. 树中节点 非红即黑
        2. 根和叶子都是黑节点(空节点算叶子),枝干非红即黑
        3. 红色节点的孩子必定是黑色,插入的结点一开始必为红色,两个红色结点不能相连
        4. 从一个节点到这个节点的任意一个子孙节点路径上包含相同个数的黑色节点。

    黑二叉树插入步骤:    

    1. 新节点统一着色为红色
        情况一:新节点为根节点
            着色为黑
        情况二:新节点的父节点颜色为黑
            啥都不干
        情况三:新节点的父节点颜色为红色
            3.1 被插入节点父节点颜色为红色,并且叔叔节点颜色为黑色,并且被插入节点是其父节点的左孩子
                3.1.1 父节点设置为黑色
                3.1.2 爷爷节点设置为红色
                3.1.3 以其父节点为轴右旋
            3.2 被插入节点父节点颜色为红色,并且叔叔节点颜色为黑色,并且被插入节点是其父节点的右孩子
                3.2.1 以其父节点为轴 ,左旋
                3.2.2 新节点设置为黑色
            3.3 被插入节点父节点颜色为红色,并且叔叔节点颜色为红色
                3.3.1 父节点设置为黑色
                3.3.2 叔叔节点设置为黑色
                3.3.3 爷爷节点设置为红色
                3.3.4 把爷爷节点当成新节点插入

    (1) 情景1:红黑树为空树

    • 将插入节点作为根节点,然后将根节点设置为黑色

    (2) 情景2:插入点的key已存在

    • 替换原节点的value值

    (3) 情景3:插入节点的父节点是黑节点

    • 直接插入,不会影响自平衡

    (4) 情景4:插入节点的父节点是红节点

    根据性质2:父节点为红色一定不是根节点;根据性质4:爷节点肯定是黑色。

             情景4.1:叔叔节点存在,且为红色

             

    • 将父节点P和叔节点U改为黑色

    • 爷节点PP改为红色。

    • 进行后续处理: 

          情景4.2:叔节点不存在或为黑节点,且插入节点的父节点是爷节点的左孩子  

                    注意:叔叔节点应该非红即空,否则破坏性质

                     情景4.2.1:插入节点是父节点的左孩子(LL双红情况)

    • 将父节点P设为黑色,将爷节点PP设为红色

    • 对爷节点PP进行右旋

                    情景4.2.1:插入节点是父节点的右孩子(LR双红情况)

    • 对父节点P进行左旋

    • 将P设为当前节点,得到LL双红情况

    • 将I设为黑色,将爷节点PP设为红色

    • 对爷节点PP进行右旋

            情景4.3:叔叔节点不存在或为黑节点,且插入节点的父节点是爷节点的右孩子

                    对应情景4.2,只是方向相反

    红黑树代码实现

    1. #include
    2. #include
    3. //辅助宏
    4. #define RED 0
    5. #define BLACK 1
    6. //获取节点的颜色
    7. #define COLOR(x) ((x)->color)
    8. //获取当前节点的父节点
    9. #define PARENTNODE(x) ((x)->parentNode)
    10. //设置当前节点的父节点
    11. #define SET_PARENT(x,p) ((x)->parentNode=(p))
    12. //设置当前节点的颜色
    13. #define SET_COLOR(x,c) ((x)->color=(c))
    14. //设置当前节点颜色为黑色
    15. #define SET_BLACK(x) ((x)->color=BLACK)
    16. //设置当前节点颜色为红色
    17. #define SET_RED(x) ((x)->color=RED)
    18. //判断当前节点颜色是否为黑色
    19. #define IS_BLACK(x) ((x)->color==BLACK)
    20. //判断当前节点颜色是否为红色
    21. #define IS_RED(x) ((x)->color==RED)
    22. //红黑树的结构体
    23. struct RBTreeNode
    24. {
    25. unsigned int color; //颜色
    26. int key; //关键字
    27. struct RBTreeNode* LChild;
    28. struct RBTreeNode* RChild;
    29. struct RBTreeNode* parentNode;
    30. }
    31. typedef struct RBTreeNode NODE;
    32. typedef struct RBTreeNode* LPNODE;
    33. struct RBTree
    34. {
    35. LPNODE root;
    36. int treeSize;
    37. }
    38. typedef struct RBTree RBTREE;
    39. typedef struct RBTree* LPRBTREE;
    40. LPNODE createNode(int key)
    41. {
    42. LPNODE newNode = (LPNODE)malloc(sizeof(NODE));
    43. newNode->key = key;
    44. newNode->LChild = NULL;
    45. newNode->RChild = NULL;
    46. newNode->parentNode = NULL;
    47. newNode->color = BLACK;
    48. return newNode;
    49. }
    50. //创建树
    51. LPRBTREE createRBTree()
    52. {
    53. LPRBTREE tree = (LPRBTREE)malloc(sizeof(RBTREE));
    54. tree->root = NULL;
    55. return tree;
    56. }
    57. //左旋
    58. void L_Rotation(LPRBTREE tree,LPNODE x)
    59. {
    60. //1.拿到x的右边 y怎么表示?
    61. LPNODE y = x->RChild;
    62. //2.y的左边成为x的右边
    63. x->RChild = y->LChild;
    64. //3.判断下y的左边是不是空的
    65. //父节点的处理
    66. if (y->LChild != NULL) {
    67. y->LChild->parentNode = x;
    68. }
    69. //y替换了x ,所以x的父节点就是y的父节点
    70. y->parentNode = x->parentNode;
    71. //如果x是根不,循环后,红黑树的根改变
    72. if (x->parentNode == NULL) {
    73. tree->root = y;
    74. }
    75. else {
    76. //不是根部判断x是在原来父节点左边还是右边
    77. if(x->parentNode->LChild==x){
    78. x->parentNode->LChild = y;
    79. }
    80. else {
    81. x->parentNode->RChild = y;
    82. }
    83. }
    84. //处理一下x的位置
    85. y->LChild = x;
    86. x->parentNode = y;
    87. }
    88. //右旋
    89. void R_Rotation(LPRBTREE tree, LPNODE y)
    90. {
    91. //拿到x节点
    92. LPNODE x = y->LChild;
    93. y->LChild = x->RChild;
    94. if (x->RChild != NULL)
    95. {
    96. x->RChild->parentNode = y;
    97. }
    98. //处理x和y的父节点
    99. x->parentNode = y->parentNode;
    100. if (y->parentNode == NULL)
    101. {
    102. tree->root = x;
    103. }
    104. else
    105. {
    106. if (y == y->parentNode->LChild)
    107. {
    108. y->parentNode->LChild = x;
    109. }
    110. else
    111. {
    112. y->parentNode->RChild = x;
    113. }
    114. }
    115. //
    116. x->RChild = y;
    117. y->parentNode = x;
    118. }
    119. //1.插入
    120. //1.1 当作BST(有序二叉树)做一个插入
    121. //1.2 调整成为红黑树
    122. void insertAdjustTree(LPRBTREE tree, LPNODE node)
    123. {
    124. LPNODE parent, gparent;
    125. while ((parent = PARENTNODE(node)) && IS_RED(parent))
    126. {
    127. gparent = PARENTNODE(parent);
    128. //三种情况分析
    129. if (parent == gparent->LChild)
    130. {//父节点是祖父节点的左孩子
    131. //No.1 U=RED;//对应笔记中的情况三 . 3
    132. {
    133. LPNODE uncle = gparent->RChild;
    134. if (uncle && IS_RED(uncle))
    135. {
    136. SET_BLACK(uncle); //uncle->color=BLACK;
    137. SET_BLACK(parent); //parent->color=BLACK;
    138. SET_RED(gparent); //gpranet->color=RED;
    139. node = gparent;
    140. continue;
    141. }
    142. }
    143. //No.2 u=BLACK S=R //对应笔记中 情况三.1
    144. if (parent->RChild == node)
    145. {
    146. LPNODE temp;
    147. L_Rotation(tree, parent);
    148. temp = parent;
    149. parent = node;
    150. node = temp;
    151. }
    152. //No.3 U=BLACK S=L //对应笔记中 情况三.2
    153. SET_BLACK(parent);
    154. SET_RED(gparent);
    155. R_Rotation(tree, gparent);
    156. }
    157. else
    158. {//父节点是祖父节点的右孩子
    159. //No.1 //对应笔记中的情况三 . 3
    160. {
    161. LPNODE uncle = gparent->LChild;
    162. if (uncle && IS_RED(uncle))
    163. {
    164. SET_BLACK(uncle); //uncle->color=BLACK;
    165. SET_BLACK(parent); //parent->color=BLACK;
    166. SET_RED(gparent); //gpranet->color=RED;
    167. node = gparent;
    168. continue;
    169. }
    170. }
    171. //No.2
    172. if (parent->LChild == node) //对应笔记中 情况三.1
    173. {
    174. LPNODE temp;
    175. R_Rotation(tree, parent);
    176. temp = parent;
    177. parent = node;
    178. node = temp;
    179. }
    180. SET_BLACK(parent);//对应笔记中 情况三.2
    181. SET_RED(gparent);
    182. L_Rotation(tree, gparent);
    183. }
    184. }
    185. SET_BLACK(tree->root);// 对应笔记中 情况一:新节点是根节点
    186. }
    187. //1.1 当作BST做一个插入
    188. void insertNode(LPRBTREE tree, LPNODE node)
    189. {
    190. //当作BST做一个插入
    191. LPNODE y = NULL;
    192. LPNODE x = tree->root;
    193. while (x != NULL)
    194. {
    195. y = x; //记录父节点
    196. if (node->key < x->key)
    197. {
    198. x = x->LChild;
    199. }
    200. else
    201. {
    202. x = x->RChild;
    203. }
    204. }
    205. //新节点应该插在y节点的下面
    206. SET_PARENT(node, y);
    207. if (y != NULL)
    208. {
    209. if (node->key < y->key)
    210. {
    211. y->LChild = node;
    212. }
    213. else
    214. {
    215. y->RChild = node;
    216. }
    217. }
    218. else //树是空的,第一次插入节点就要成为根节点
    219. {
    220. tree->root = node;
    221. }
    222. SET_COLOR(node, RED); //插入节点着色红色
    223. //2.按照红黑树的规则情况去调整二叉树成为红黑树
    224. insertAdjustTree(tree, node);
    225. }
    226. void printCurNode(LPNODE curNode)
    227. {
    228. printf("%d:%s\n", curNode->key, curNode->color ? "BLACK" : "RED");
    229. }
    230. void preOrder(LPNODE root)
    231. {
    232. if (root != NULL)
    233. {
    234. printCurNode(root); //printf("%d:%s\n", curNode->key, curNode->color ? "BLACK" : "RED");
    235. preOrder(root->LChild);
    236. preOrder(root->RChild);
    237. }
    238. }
    239. //2.红黑树的删除
    240. //2.1 当做BST 去做删除
    241. //2.2 调整
    242. void deleteAdjustTree(LPRBTREE tree, LPNODE node, LPNODE parent)
    243. {
    244. LPNODE other;
    245. while (!node || IS_BLACK(node) && node != tree->root)
    246. {
    247. if (parent->LChild == node) //node是其父节点的左孩子
    248. {
    249. other = parent->RChild;
    250. if (IS_RED(other))//node的兄弟为红色节点
    251. {
    252. //No.1 xB=RED
    253. SET_BLACK(other);
    254. SET_RED(parent);
    255. L_Rotation(tree, parent);
    256. other = parent->RChild;
    257. }
    258. if ((!other->LChild) || IS_BLACK(other->LChild) &&
    259. (!other->RChild) || IS_BLACK(other->RChild))
    260. {
    261. //No.2 xB=BLACK
    262. SET_RED(other);
    263. node = parent;
    264. parent = PARENTNODE(node);
    265. }
    266. else
    267. {
    268. if (!other->RChild || IS_BLACK(other->RChild))
    269. {
    270. //No.3 xB=BLACK xB->LChild=RED, xB->RChild=BLACK;
    271. SET_BLACK(other->LChild);
    272. SET_RED(other);
    273. R_Rotation(tree, other);
    274. other = parent->RChild;
    275. }
    276. //No.4 xB=BLACK xB=RChild=RED
    277. SET_COLOR(other, COLOR(parent));
    278. SET_BLACK(parent);
    279. SET_BLACK(other->RChild);
    280. L_Rotation(tree, parent);
    281. node = tree->root;
    282. break;
    283. }
    284. }
    285. else //node是其父节点的右孩子
    286. {
    287. other = parent->LChild;
    288. if (IS_RED(other))
    289. {
    290. //No.1 xB=RED
    291. SET_BLACK(other);
    292. SET_RED(parent);
    293. L_Rotation(tree, parent);
    294. other = parent->LChild;
    295. }
    296. if ((!other->LChild) || IS_BLACK(other->LChild) &&
    297. (!other->RChild) || IS_BLACK(other->RChild))
    298. {
    299. //No.2 xB=BLACK
    300. SET_RED(other);
    301. node = parent;
    302. parent = PARENTNODE(node);
    303. }
    304. else
    305. {
    306. if (!other->LChild || IS_BLACK(other->LChild))
    307. {
    308. //No.3 xB=BLACK xB->RChild=RED, xB->LChild=BLACK;
    309. SET_BLACK(other->RChild);
    310. SET_RED(other);
    311. L_Rotation(tree, other);
    312. other = parent->LChild;
    313. }
    314. //No.4 xB=BLACK xB=LChild=RED
    315. SET_COLOR(other, COLOR(parent));
    316. SET_BLACK(parent);
    317. SET_BLACK(other->LChild);
    318. R_Rotation(tree, parent);
    319. node = tree->root;
    320. break;
    321. }
    322. }
    323. }
    324. if (node)
    325. {
    326. SET_BLACK(node);
    327. }
    328. }
    329. //2.1 当做BST 去做删除
    330. void deleteNode(LPRBTREE tree, LPNODE node)
    331. {
    332. LPNODE child, parent;
    333. int color; //删除节点兄弟的颜色
    334. //左右子树都存在
    335. if ((node->LChild) != NULL && (node->RChild) != NULL)
    336. {
    337. LPNODE replace = node;
    338. replace = replace->RChild; //调整树:从右子树中拿最左边
    339. while (replace->LChild != NULL)
    340. {
    341. replace = replace->LChild;
    342. }
    343. //讨论删除节点是不是根节点
    344. if (PARENTNODE(node))
    345. {
    346. if (PARENTNODE(node)->LChild == node)
    347. {
    348. PARENTNODE(node)->LChild = replace;
    349. }
    350. else
    351. {
    352. PARENTNODE(node)->RChild = replace;
    353. }
    354. }
    355. else
    356. {
    357. tree->root = replace;
    358. }
    359. child = replace->RChild;
    360. parent = PARENTNODE(replace);
    361. color = COLOR(replace);
    362. if (parent == node)
    363. {
    364. parent = replace;
    365. }
    366. else
    367. {
    368. if (child)
    369. {
    370. SET_PARENT(child, parent);
    371. }
    372. parent->LChild = child;
    373. replace->RChild = node->RChild;
    374. SET_PARENT(node->RChild, replace);
    375. }
    376. //调整替换节点父节点
    377. replace->parentNode = node->parentNode;
    378. replace->color = node->color;
    379. replace->LChild = node->LChild;
    380. //调整删除节点父节点
    381. node->LChild->parentNode = replace;
    382. if (color == BLACK)
    383. {
    384. //调整树:
    385. deleteAdjustTree(tree, child, parent);
    386. }
    387. free(node);
    388. return;
    389. }
    390. if (node->LChild != NULL)
    391. {
    392. child = node->LChild;
    393. }
    394. else
    395. {
    396. child = node->RChild;
    397. }
    398. parent = node->parentNode;
    399. color = node->color;
    400. if (parent)
    401. {
    402. if (parent->LChild == node)
    403. {
    404. parent->LChild = child;
    405. }
    406. else
    407. {
    408. parent->RChild = child;
    409. }
    410. }
    411. else
    412. {
    413. tree->root = child;
    414. }
    415. if (color == BLACK)
    416. {
    417. //调整二叉树
    418. deleteAdjustTree(tree, child, parent);
    419. }
    420. free(node);
    421. }
    422. LPNODE search(LPNODE x, int key)
    423. {
    424. if (x == NULL || x->key == key)
    425. return x;
    426. if (key < x->key)
    427. {
    428. return search(x->LChild, key);
    429. }
    430. else
    431. {
    432. return search(x->RChild, key);
    433. }
    434. }
    435. void deleteTreeNode(LPRBTREE tree, int key)
    436. {
    437. LPNODE result = search(tree->root, key);
    438. if (result != NULL)
    439. deleteNode(tree, result);
    440. }
    441. int main()
    442. {
    443. int array[] = {10,40,30,60,90,70,20,50,80};
    444. int arrayNum = 9;
    445. LPRBTREE tree = createRBTree();
    446. for (int i = 0; i < arrayNum; i++)
    447. {
    448. insertNode(tree, createNode(array[i]));
    449. }
    450. preOrder(tree->root);
    451. printf("\n");
    452. printf("删除:\n");
    453. deleteTreeNode(tree, 10);
    454. preOrder(tree->root);
    455. printf("\n");
    456. printf("删除:\n");
    457. deleteTreeNode(tree, 80);
    458. preOrder(tree->root);
    459. printf("\n");
    460. while(1);//防止闪屏
    461. return 0;
    462. }

  • 相关阅读:
    Ubuntu下载、安装QGIS软件的方法
    使用python生成文字图片,画圆圈 ,生成圆形图片
    前端多环境部署
    IntelliJ IDEA 2023.1 版本可以安装了
    STM32F1读取MLX90632非接触式红外温度传感器
    MyBatis——表的关联关系,事务,ORM,缓存机制
    ESP32网络开发实例-Web服务器控制GPIO
    猿创征文 |《深入浅出Vue.js》打卡Day6
    HoG(梯度直方图)原理及python实现
    Java虚拟机二三事:虚拟机类加载机制
  • 原文地址:https://blog.csdn.net/zjjaibc/article/details/126399611