• 红黑树(Red Black Tree)


    一、简介

            红黑树是一种自平衡的二叉查找树。除了符合二叉查找树的基本特性外,还具有以下特性:

    1. 结点是红色或黑色。
    2. 根结点是黑色。
    3. 每个叶子结点都是黑色的空结点(NIL结点)。 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
    4. 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

            图1就是一个红黑树的样例:

    图1 - 红黑树示意图

    二、相关操作

    一、插入 

            正是因为这些条条框框的规则限制,才保证了红黑树的自平衡。红黑树从根到叶子的最长路径不超过最短路径的2倍。当插入或删除节点时,红黑树的规则又可能会被打破。这时候就需要进行调整来维持我们的规则。图2就是一种样例。

    图2 - 打破规则的红黑树

             那我们怎样才能调整红黑树,让它始终保持是红黑树呢?

            调整方法有两种:变色或者旋转(包含左旋转和右旋转)。

    变色

            为重新符合红黑树的规则,我们只需要尝试把红色节点变为黑色节点,把黑色节点编程红色节点。

            如图3所示,新叉入的y是红色节点,他的父节点x不符合规则,所以要把x从红色变成黑色。

    图3 - 变色示意图

             单仅仅一个变色,就可能导致凭空多出来一个黑色节点,所以我们需要对其他节点进行进一步调整,也就是旋转。

    左旋转

            逆时针旋转红黑树的两个节点,使父节点被右孩子节点代替,二孩子称为自己孩子的左孩子节点。说起来有点难,看图4能更好理解。

    图4 - 左旋转示意图

             其中,身为右孩子的y取代了x,x又变成了自己的左孩子。这就是左旋转。

    右旋转 

            顺时针旋转红黑树的两个节点,使得父节点被左孩子节点取代,而自己成为自己的右孩子

    图5 - 右旋转示意图

            图中,身为左孩子的y取代了x的位置,而x变成了自己的右孩子。这就是右旋转。

     二、删除

            对以上算法分析,若删除的结点是红色,则不做任何操作,红黑树的任何属性都不会被破坏;若删除的结点是黑色的,显然它所 在的路径上就少一个黑色结点,红黑树的性质就被破坏了,这时执行一个 Delete-Fixup()来修补这棵树。 一个结点被删除之后,一定 有一个它的结点代替了它的位置,即使是叶结点被删除后,也会有一个空结点来代替它的位置。 设指针 x 指向这个代替位置的结点,同时引入指向 x 兄弟的指针 w,这里均假设 x 是 x->parent 的左子结点,则 w 是 x->parent 的右子结点,如果实际遇到相反的情 况,只要把所有操作中的左、右互反一下就可以了。

    三、代码实现

    1. #include
    2. #include
    3. #include "rbtree.h"
    4. #define rb_parent(r) ((r)->parent)
    5. #define rb_color(r) ((r)->color)
    6. #define rb_is_red(r) ((r)->color==RED)
    7. #define rb_is_black(r) ((r)->color==BLACK)
    8. #define rb_set_black(r) do { (r)->color = BLACK; } while (0)
    9. #define rb_set_red(r) do { (r)->color = RED; } while (0)
    10. #define rb_set_parent(r,p) do { (r)->parent = (p); } while (0)
    11. #define rb_set_color(r,c) do { (r)->color = (c); } while (0)
    12. /*
    13. * 创建红黑树,返回"红黑树的根"!
    14. */
    15. RBRoot* create_rbtree()
    16. {
    17. RBRoot *root = (RBRoot *)malloc(sizeof(RBRoot));
    18. root->node = NULL;
    19. return root;
    20. }
    21. /*
    22. * 前序遍历"红黑树"
    23. */
    24. static void preorder(RBTree tree)
    25. {
    26. printf("(");
    27. if(tree != NULL)
    28. {
    29. printf("%d%c", tree->key,tree->color?' ':'+');
    30. preorder(tree->left);
    31. preorder(tree->right);
    32. }
    33. printf(")");
    34. }
    35. void preorder_rbtree(RBRoot *root)
    36. {
    37. if (root)
    38. preorder(root->node);
    39. }
    40. /*
    41. * (递归实现)查找"红黑树x"中键值为key的节点
    42. */
    43. static Node* search(RBTree x, Type key)
    44. {
    45. if (x==NULL || x->key==key)
    46. return x;
    47. if (key < x->key)
    48. return search(x->left, key);
    49. else
    50. return search(x->right, key);
    51. }
    52. int rbtree_search(RBRoot *root, Type key)
    53. {
    54. if (root)
    55. return search(root->node, key)? 0 : -1;
    56. }
    57. /*
    58. * (非递归实现)查找"红黑树x"中键值为key的节点
    59. */
    60. static Node* iterative_search(RBTree x, Type key)
    61. {
    62. while ((x!=NULL) && (x->key!=key))
    63. {
    64. if (key < x->key)
    65. x = x->left;
    66. else
    67. x = x->right;
    68. }
    69. return x;
    70. }
    71. int iterative_rbtree_search(RBRoot *root, Type key)
    72. {
    73. if (root)
    74. return iterative_search(root->node, key) ? 0 : -1;
    75. }
    76. /*
    77. * 查找最小结点:返回tree为根结点的红黑树的最小结点。
    78. */
    79. static Node* minimum(RBTree tree)
    80. {
    81. if (tree == NULL)
    82. return NULL;
    83. while(tree->left != NULL)
    84. tree = tree->left;
    85. return tree;
    86. }
    87. int rbtree_minimum(RBRoot *root, int *val)
    88. {
    89. Node *node;
    90. if (root)
    91. node = minimum(root->node);
    92. if (node == NULL)
    93. return -1;
    94. *val = node->key;
    95. return 0;
    96. }
    97. /*
    98. * 查找最大结点:返回tree为根结点的红黑树的最大结点。
    99. */
    100. static Node* maximum(RBTree tree)
    101. {
    102. if (tree == NULL)
    103. return NULL;
    104. while(tree->right != NULL)
    105. tree = tree->right;
    106. return tree;
    107. }
    108. int rbtree_maximum(RBRoot *root, int *val)
    109. {
    110. Node *node;
    111. if (root)
    112. node = maximum(root->node);
    113. if (node == NULL)
    114. return -1;
    115. *val = node->key;
    116. return 0;
    117. }
    118. /*
    119. * 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。
    120. */
    121. static Node* rbtree_successor(RBTree x)
    122. {
    123. // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
    124. if (x->right != NULL)
    125. return minimum(x->right);
    126. // 如果x没有右孩子。则x有以下两种可能:
    127. // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
    128. // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
    129. Node* y = x->parent;
    130. while ((y!=NULL) && (x==y->right))
    131. {
    132. x = y;
    133. y = y->parent;
    134. }
    135. return y;
    136. }
    137. /*
    138. * 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。
    139. */
    140. static Node* rbtree_predecessor(RBTree x)
    141. {
    142. // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
    143. if (x->left != NULL)
    144. return maximum(x->left);
    145. // 如果x没有左孩子。则x有以下两种可能:
    146. // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
    147. // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
    148. Node* y = x->parent;
    149. while ((y!=NULL) && (x==y->left))
    150. {
    151. x = y;
    152. y = y->parent;
    153. }
    154. return y;
    155. }
    156. /*
    157. * 对红黑树的节点(x)进行左旋转
    158. *
    159. * 左旋示意图(对节点x进行左旋):
    160. * px px
    161. * / /
    162. * x y
    163. * / \ --(左旋)--> / \ #
    164. * lx y x ry
    165. * / \ / \
    166. * ly ry lx ly
    167. *
    168. *
    169. */
    170. static void rbtree_left_rotate(RBRoot *root, Node *x)
    171. {
    172. // 设置x的右孩子为y
    173. Node *y = x->right;
    174. // 将 “y的左孩子” 设为 “x的右孩子”;
    175. // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”
    176. x->right = y->left;
    177. if (y->left != NULL)
    178. y->left->parent = x;
    179. // 将 “x的父亲” 设为 “y的父亲”
    180. y->parent = x->parent;
    181. if (x->parent == NULL)//修改红黑树的根节点
    182. {
    183. //tree = y; // 如果 “x的父亲” 是空节点,则将y设为根节点
    184. root->node = y; // 如果 “x的父亲” 是空节点,则将y设为根节点
    185. }
    186. else
    187. {
    188. if (x->parent->left == x)
    189. x->parent->left = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
    190. else
    191. x->parent->right = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”
    192. }
    193. // 将 “x” 设为 “y的左孩子”
    194. y->left = x;
    195. // 将 “x的父节点” 设为 “y”
    196. x->parent = y;
    197. }
    198. /*
    199. * 对红黑树的节点(y)进行右旋转
    200. *
    201. * 右旋示意图(对节点y进行左旋):
    202. * py py
    203. * / /
    204. * y x
    205. * / \ --(右旋)--> / \ #
    206. * x ry lx y
    207. * / \ / \ #
    208. * lx rx rx ry
    209. *
    210. */
    211. static void rbtree_right_rotate(RBRoot *root, Node *y)
    212. {
    213. // 设置x是当前节点的左孩子。
    214. Node *x = y->left;
    215. // 将 “x的右孩子” 设为 “y的左孩子”;
    216. // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”
    217. y->left = x->right;
    218. if (x->right != NULL)
    219. x->right->parent = y;
    220. // 将 “y的父亲” 设为 “x的父亲”
    221. x->parent = y->parent;
    222. if (y->parent == NULL)
    223. {
    224. //tree = x; // 如果 “y的父亲” 是空节点,则将x设为根节点
    225. root->node = x; // 如果 “y的父亲” 是空节点,则将x设为根节点
    226. }
    227. else
    228. {
    229. if (y == y->parent->right)
    230. y->parent->right = x; // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”
    231. else
    232. y->parent->left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”
    233. }
    234. // 将 “y” 设为 “x的右孩子”
    235. x->right = y;
    236. // 将 “y的父节点” 设为 “x”
    237. y->parent = x;
    238. }
    239. /*
    240. * 红黑树插入修正函数
    241. *
    242. * 在向红黑树中插入节点之后(失去平衡),再调用该函数;
    243. * 目的是将它重新塑造成一颗红黑树。
    244. *
    245. * 参数说明:
    246. * root 红黑树的根
    247. * node 插入的结点 // 对应《算法导论》中的z
    248. */
    249. static void rbtree_insert_fixup(RBRoot *root, Node *node)
    250. {
    251. Node *parent, *gparent;
    252. // 若“父节点存在,并且父节点的颜色是红色”
    253. while ((parent = rb_parent(node)) && rb_is_red(parent))
    254. {
    255. gparent = rb_parent(parent);
    256. //若“父节点”是“祖父节点的左孩子”
    257. if (parent == gparent->left)
    258. {
    259. // Case 1条件:叔叔节点是红色
    260. {
    261. Node *uncle = gparent->right;
    262. if (uncle && rb_is_red(uncle))//没有节点进入该分支,如何构造?
    263. {
    264. rb_set_black(uncle);
    265. rb_set_black(parent);
    266. rb_set_red(gparent);
    267. node = gparent;
    268. continue;
    269. }
    270. }
    271. // Case 2条件:叔叔是黑色,且当前节点是右孩子,叔叔不存在,也认为是黑色
    272. if (parent->right == node)//插入80节点时,先左旋,后右旋
    273. {
    274. Node *tmp;
    275. rbtree_left_rotate(root, parent);
    276. tmp = parent;
    277. parent = node;
    278. node = tmp;
    279. }
    280. // Case 3条件:叔叔是黑色,且当前节点是左孩子。
    281. rb_set_black(parent);//旋转前设置好颜色
    282. rb_set_red(gparent);//旋转前设置好颜色
    283. rbtree_right_rotate(root, gparent);
    284. }
    285. else//若父节点是祖父节点的右孩子
    286. {
    287. // Case 1条件:叔叔节点是红色
    288. {
    289. Node *uncle = gparent->left;//当插入60时,调整颜色即可,调整颜色后不符合红黑树,递归进行
    290. if (uncle && rb_is_red(uncle))
    291. {
    292. rb_set_black(uncle);
    293. rb_set_black(parent);
    294. rb_set_red(gparent);
    295. node = gparent;
    296. continue;//继续进行调整
    297. }
    298. }
    299. // Case 2条件:叔叔是黑色,且当前节点是左孩子,插入30时,先右旋,后左旋
    300. if (parent->left == node)
    301. {
    302. Node *tmp;
    303. rbtree_right_rotate(root, parent);
    304. tmp = parent;
    305. parent = node;
    306. node = tmp;
    307. }
    308. // Case 3条件:叔叔是黑色,且当前节点是右孩子。
    309. rb_set_black(parent);//旋转前设置好颜色
    310. rb_set_red(gparent);//旋转前设置好颜色
    311. rbtree_left_rotate(root, gparent);
    312. }
    313. }
    314. // 将根节点设为黑色
    315. rb_set_black(root->node);
    316. }
    317. /*
    318. * 添加节点:将节点(node)插入到红黑树中
    319. *
    320. * 参数说明:
    321. * root 红黑树的根
    322. * node 插入的结点 // 对应《算法导论》中的z
    323. */
    324. static void rbtree_insert(RBRoot *root, Node *node)
    325. {
    326. Node *y = NULL;
    327. Node *x = root->node;
    328. // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。
    329. while (x != NULL)
    330. {
    331. y = x;
    332. if (node->key < x->key)
    333. x = x->left;
    334. else
    335. x = x->right;
    336. }
    337. rb_parent(node) = y;//找到父节点并把要插入节点的父节点的指针修改
    338. //修改父节点的子节点指针
    339. if (y != NULL)
    340. {
    341. if (node->key < y->key)
    342. y->left = node; // 情况2:若“node所包含的值” < “y所包含的值”,则将node设为“y的左孩子”
    343. else
    344. y->right = node; // 情况3:(“node所包含的值” >= “y所包含的值”)将node设为“y的右孩子”
    345. }
    346. else
    347. {
    348. root->node = node; // 情况1:若y是空节点,则将node设为根
    349. }
    350. // 2. 设置节点的颜色为红色
    351. node->color = RED;
    352. // 3. 将它重新修正为一颗二叉查找树
    353. rbtree_insert_fixup(root, node);
    354. }
    355. /*
    356. * 创建结点
    357. *
    358. * 参数说明:
    359. * key 是键值。
    360. * parent 是父结点。
    361. * left 是左孩子。
    362. * right 是右孩子。
    363. */
    364. static Node* create_rbtree_node(Type key, Node *parent, Node *left, Node* right)
    365. {
    366. Node* p;
    367. if ((p = (Node *)malloc(sizeof(Node))) == NULL)
    368. return NULL;
    369. p->key = key;
    370. p->left = left;
    371. p->right = right;
    372. p->parent = parent;
    373. p->color = BLACK; // 默认为黑色
    374. return p;
    375. }
    376. /*
    377. * 新建结点(节点键值为key),并将其插入到红黑树中
    378. *
    379. * 参数说明:
    380. * root 红黑树的根
    381. * key 插入结点的键值
    382. * 返回值:
    383. * 0,插入成功
    384. * -1,插入失败
    385. */
    386. int insert_rbtree(RBRoot *root, Type key)
    387. {
    388. Node *node; // 新建结点
    389. // 不允许插入相同键值的节点。
    390. // (若想允许插入相同键值的节点,注释掉下面两句话即可!)
    391. if (search(root->node, key) != NULL)
    392. return -1;
    393. // 如果新建结点失败,则返回。
    394. if ((node=create_rbtree_node(key, NULL, NULL, NULL)) == NULL)
    395. return -1;
    396. rbtree_insert(root, node);
    397. return 0;
    398. }
    399. /*
    400. * 红黑树删除修正函数
    401. *
    402. * 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数;
    403. * 目的是将它重新塑造成一颗红黑树。
    404. *
    405. * 参数说明:
    406. * root 红黑树的根
    407. * node 待修正的节点
    408. */
    409. static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *parent)
    410. {
    411. Node *other;
    412. while ((!node || rb_is_black(node)) && node != root->node)
    413. {
    414. if (parent->left == node)
    415. {
    416. other = parent->right;
    417. if (rb_is_red(other))
    418. {
    419. // Case 1: x的兄弟w是红色的
    420. rb_set_black(other);
    421. rb_set_red(parent);
    422. rbtree_left_rotate(root, parent);
    423. other = parent->right;
    424. }
    425. if ((!other->left || rb_is_black(other->left)) &&
    426. (!other->right || rb_is_black(other->right)))
    427. {
    428. // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
    429. rb_set_red(other);
    430. node = parent;
    431. parent = rb_parent(node);
    432. }
    433. else
    434. {
    435. if (!other->right || rb_is_black(other->right))
    436. {
    437. // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
    438. rb_set_black(other->left);
    439. rb_set_red(other);
    440. rbtree_right_rotate(root, other);
    441. other = parent->right;
    442. }
    443. // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
    444. rb_set_color(other, rb_color(parent));
    445. rb_set_black(parent);
    446. rb_set_black(other->right);
    447. rbtree_left_rotate(root, parent);
    448. node = root->node;
    449. break;
    450. }
    451. }
    452. else
    453. {
    454. other = parent->left;
    455. if (rb_is_red(other))
    456. {
    457. // Case 1: x的兄弟w是红色的
    458. rb_set_black(other);
    459. rb_set_red(parent);
    460. rbtree_right_rotate(root, parent);
    461. other = parent->left;
    462. }
    463. if ((!other->left || rb_is_black(other->left)) &&
    464. (!other->right || rb_is_black(other->right)))
    465. {
    466. // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的
    467. rb_set_red(other);
    468. node = parent;
    469. parent = rb_parent(node);
    470. }
    471. else
    472. {
    473. if (!other->left || rb_is_black(other->left))
    474. {
    475. // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。
    476. rb_set_black(other->right);
    477. rb_set_red(other);
    478. rbtree_left_rotate(root, other);
    479. other = parent->left;
    480. }
    481. // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。
    482. rb_set_color(other, rb_color(parent));
    483. rb_set_black(parent);
    484. rb_set_black(other->left);
    485. rbtree_right_rotate(root, parent);
    486. node = root->node;
    487. break;
    488. }
    489. }
    490. }
    491. if (node)
    492. rb_set_black(node);
    493. }
    494. /*
    495. * 删除结点
    496. *
    497. * 参数说明:
    498. * tree 红黑树的根结点
    499. * node 删除的结点
    500. */
    501. void rbtree_delete(RBRoot *root, Node *node)
    502. {
    503. Node *child, *parent;
    504. int color;
    505. // 被删除节点的"左右孩子都不为空"的情况。
    506. if ( (node->left!=NULL) && (node->right!=NULL) )
    507. {
    508. // 被删节点的后继节点。(称为"取代节点")
    509. // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。
    510. Node *replace = node;
    511. // 获取后继节点
    512. replace = replace->right;
    513. while (replace->left != NULL)
    514. replace = replace->left;
    515. // "node节点"不是根节点(只有根节点不存在父节点)
    516. if (rb_parent(node))
    517. {
    518. if (rb_parent(node)->left == node)
    519. rb_parent(node)->left = replace;
    520. else
    521. rb_parent(node)->right = replace;
    522. }
    523. else
    524. // "node节点"是根节点,更新根节点。
    525. root->node = replace;
    526. // child是"取代节点"的右孩子,也是需要"调整的节点"。
    527. // "取代节点"肯定不存在左孩子!因为它是一个后继节点。
    528. child = replace->right;
    529. parent = rb_parent(replace);
    530. // 保存"取代节点"的颜色
    531. color = rb_color(replace);
    532. // "被删除节点"是"它的后继节点的父节点"
    533. if (parent == node)
    534. {
    535. parent = replace;
    536. }
    537. else
    538. {
    539. // child不为空
    540. if (child)
    541. rb_set_parent(child, parent);
    542. parent->left = child;
    543. replace->right = node->right;
    544. rb_set_parent(node->right, replace);
    545. }
    546. replace->parent = node->parent;
    547. replace->color = node->color;
    548. replace->left = node->left;
    549. node->left->parent = replace;
    550. if (color == BLACK)
    551. rbtree_delete_fixup(root, child, parent);
    552. free(node);
    553. return ;
    554. }
    555. if (node->left !=NULL)
    556. child = node->left;
    557. else
    558. child = node->right;
    559. parent = node->parent;
    560. // 保存"取代节点"的颜色
    561. color = node->color;
    562. if (child)
    563. child->parent = parent;
    564. // "node节点"不是根节点
    565. if (parent)
    566. {
    567. if (parent->left == node)
    568. parent->left = child;
    569. else
    570. parent->right = child;
    571. }
    572. else
    573. root->node = child;
    574. if (color == BLACK)
    575. rbtree_delete_fixup(root, child, parent);
    576. free(node);
    577. }
    578. /*
    579. * 删除键值为key的结点
    580. *
    581. * 参数说明:
    582. * tree 红黑树的根结点
    583. * key 键值
    584. */
    585. void delete_rbtree(RBRoot *root, Type key)
    586. {
    587. Node *z, *node;
    588. if ((z = search(root->node, key)) != NULL)
    589. rbtree_delete(root, z);
    590. }
    591. /*
    592. * 销毁红黑树
    593. */
    594. static void rbtree_destroy(RBTree tree)
    595. {
    596. if (tree==NULL)
    597. return ;
    598. if (tree->left != NULL)
    599. rbtree_destroy(tree->left);
    600. if (tree->right != NULL)
    601. rbtree_destroy(tree->right);
    602. free(tree);
    603. }
    604. void destroy_rbtree(RBRoot *root)
    605. {
    606. if (root != NULL)
    607. rbtree_destroy(root->node);
    608. free(root);
    609. }
    610. /**
    611. * C语言实现的红黑树(Red Black Tree)
    612. *
    613. * @author skywang
    614. * @date 2013/11/18
    615. */
    616. #define CHECK_INSERT 1 // "插入"动作的检测开关(0,关闭;1,打开)
    617. #define CHECK_DELETE 1 // "删除"动作的检测开关(0,关闭;1,打开)
    618. #define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) )
    619. void main()
    620. {
    621. int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
    622. int i, ilen=LENGTH(a);
    623. RBRoot *root=NULL;
    624. root = create_rbtree();
    625. printf("== 原始数据: ");
    626. for(i=0; i
    627. printf("%d ", a[i]);
    628. printf("\n");
    629. for(i=0; i
    630. {
    631. insert_rbtree(root, a[i]);
    632. #if CHECK_INSERT
    633. printf("== 添加节点: %d\n", a[i]);
    634. printf("\n");
    635. #endif
    636. }
    637. printf("\t\\tree"); preorder_rbtree(root); printf("\n**********************\n");
    638. if (rbtree_minimum(root, &i)==0)
    639. printf("== 最小值: %d\n", i);
    640. if (rbtree_maximum(root, &i)==0)
    641. printf("== 最大值: %d\n", i);
    642. printf("\n");
    643. #endif
    644. delete_rbtree(root, 80);
    645. printf("== 删除节点: %d\n", 80);
    646. printf("\t\\tree"); preorder_rbtree(root); printf("\n********删除节点**************\n");
    647. destroy_rbtree(root);
    648. }

    声明:上述代码改编自下链接。红黑树代码_ECHO_START_END_TIME的博客-CSDN博客_红黑树代码first#include #include #include "rbtree.h" #define rb_parent(r) ((r)->parent)#define rb_color(r) ((r)->color)#define rb_is_red(r) ((r)->color==RED)#define rb_is_black(r) ((r)->color==BLACK)#define rbhttps://blog.csdn.net/weixin_44748127/article/details/123882575


    感谢阅读! 

  • 相关阅读:
    js实现页面元素的拖拽
    中国石油大学(北京)-《 油层物理》第二阶段在线作业
    【Proteus仿真】【STM32单片机】大棚远程监测控制
    Spring bean 的生命周期(总结)
    基于Python实现并对比线性分类器与非线性分类器
    别处拿来的VUE项目 npm run serve报错
    SAP 电商云 Spartacus UI 和 Accelerator UI 里的 ASM 模块
    2022年全国大学生数学建模竞赛A题思路
    VMware Workstation 与 Device/Credential Guard 不兼容 解决办法
    从软件工程的角度比较Swift、Go和Julia,我有了这些发现
  • 原文地址:https://blog.csdn.net/weixin_46522531/article/details/126630477