当前位置:   article > 正文

数据结构- 红黑树插入和调整_更改红黑树插入顺序,树是否相同

更改红黑树插入顺序,树是否相同

前面的提到了红黑树的结构定义还有旋转,其中包括左旋和右旋, 那么接下来就是插入并且做调整。

一: 插入逻辑

  • 从根节点出发,若根节点是空节点,则根节点为插入节点
  • 根节点不为空,则遍历树,以key值为大小,直到空节点,返回空节点的父节点, 遍历结束;
  • 若插入节点的key小于父节点的key, 则插入父节点的左子树, 并让插入节点的左右子树指向空节点
  • 若插入节点的key小于父节点的key, 则插入父节点的右子树, 并让插入节点的左右子树指向空节点
  • 插入节点的颜色为红色

这里的处理逻辑就是不断遍历左右子树,然后找到最下面的nil节点为止,那么其上的父节点就是要考虑的插入位置,最后再考虑一下左右即可。

注意插入的节点默认都是红色,保证其他子树的黑色数量一致,也不违背根节点是黑色等条件,但是可能违背父子节点不能是红色,因此后续需要调整。

  1. void rbtree_insert(rbtree_t *T, rbtree_node_t *z) {
  2. //遍历的节点
  3. rbtree_node_t *x = T->root;
  4. //y用于保存要插入的位置的父节点
  5. rbtree_node_t *y = T->nil;
  6. while(x != T->nil) {
  7. y = x;
  8. if (x->key > z->key){
  9. x = x->left;
  10. }else if(x->key < z->key){
  11. x = x->right;
  12. }else{
  13. //Exist
  14. return;
  15. }
  16. }
  17. if (y== T->nil) {
  18. //空树
  19. T->root = z;
  20. } else {
  21. if (y->key > z->key) {
  22. y->left = z;
  23. } else {
  24. y->right = z;
  25. }
  26. }
  27. z->parent = y;
  28. //下面设置z属性
  29. z->left = T->nil;
  30. z->right = T->nil;
  31. //插入的颜色默认是红色,保证不会改变黑色节点的路径
  32. //但是可能不满足父子节点不能同时为红色的限制,因此后续需要考虑调整
  33. z->color = RED;
  34. rbtree_insert_fixup(T, z);
  35. }

二: 节点调整

对于节点的调整,因为插入节点是红色的,因此只有在其父节点也是红色的情况下才需要调整。同时其祖父节点(即父节点的父节点)一定是黑色的,但是祖父节点的另一个子节点,即叔父节点的颜色则是不确定的,因此可以从叔父节点的颜色入手考虑。

2.1. 叔父节点也是红色

这里要调整就是祖父节点和其子节点颜色对换即可,方式如下所示:

 那么这里的简易处理逻辑如下:

  1. // rbtree_node_t *z 是插入的节点
  2. //叔父节点
  3. rbtree_node_t *y = z->parent->parent->right;
  4. if (y->color == RED) {
  5. z->parent->color = BLACK;
  6. y->color = BLACK;
  7. z->parent->parent->color =RED;
  8. //回溯z,保证回溯到z都是红色的
  9. z = z->parent->parent;
  10. }

要注意这里最后 z = z->parent->parent 这段代码,这里是因为下面的子树解决了,但是上层可能又有冲突,例如祖父节点的父节点也是红色,因此这时候还要继续迭代考虑。

2.2. 叔父节点是黑色

对于叔父节点是黑色的时候,这里还要分情况, 因为要分左右子树的情况,下面是左子树的情况:

这里迭代到z节点,然后和父节点都说红色并且在左子树。那么这里需要做两步:

  1. z的父节点和祖父节点颜色对换
  2. 以z的祖父节点(红色)进行右旋

下面是右子树的情况:

这里要做的事情有两件:

  1. 把z节点改为其父节点
  2. 以新的z节点进行左旋

这时候得到的新的树,就是第一种情况,也就是父子节点都是红色的,并且在左子树。在下次递归的时候就可以进行处理了。

下面是调整函数的完整代码:

  1. void rbtree_insert_fixup(rbtree *T, rbtree_node_t *z)
  2. {
  3. // 父子节点都是红色的, 祖父节点必然是黑色的
  4. // 但是叔父节点(即祖父节点的另一个子节点)颜色未知
  5. if (z->color == RED)
  6. {
  7. while (z->parent->color == RED)
  8. {
  9. if (z->parent->parent->left == z->parent)
  10. {
  11. // 父节点在祖父节点的左子树下
  12. // 叔父节点
  13. rbtree_node_t *y = z->parent->parent->right;
  14. if (y->color == RED)
  15. {
  16. // 叔父节点也是红色的 --> 祖父节点和其子节点颜色对调
  17. z->parent->color = BLACK;
  18. y->color = BLACK;
  19. z->parent->parent->color = RED;
  20. // 回溯z,保证回溯到z都是红色的
  21. z = z->parent->parent;
  22. }
  23. else
  24. {
  25. // 叔父节点是黑色的 --> 区分z是在左还是右子树
  26. if (z == z->parent->left)
  27. {
  28. // z节点在左子树下
  29. // 1).对换父节点和祖父节点颜色
  30. z->parent->color = BLACK;
  31. z->parent->parent->color = RED;
  32. // 2). 以祖父节点进行右旋
  33. rbtree_right_roate(T, z->parent->parent);
  34. }
  35. else
  36. {
  37. // z节点在右子树下
  38. // 1). 把z改为其父节点
  39. z = z->parent;
  40. // 2). 进行左旋
  41. rbtree_left_roate(T, z);
  42. }
  43. }
  44. }
  45. else
  46. {
  47. // 叔父节点
  48. rbtree_node_t *y = z->parent->parent->left;
  49. if (y->color == RED)
  50. {
  51. // 叔父节点也是红色的 --> 祖父节点和其子节点颜色对调
  52. z->parent->color = BLACK;
  53. y->color = BLACK;
  54. z->parent->parent->color = RED;
  55. // 回溯z,保证回溯到z都是红色的
  56. z = z->parent->parent;
  57. }
  58. else
  59. {
  60. //和上面的情况对比,则是左右对调, 左右旋互换
  61. if (z == z->parent->right)
  62. {
  63. z->parent->color = BLACK;
  64. z->parent->parent->color = RED;
  65. rbtree_left_roate(T, z->parent->parent);
  66. }
  67. else
  68. {
  69. z = z->parent;
  70. rbtree_right_roate(T, z);
  71. }
  72. }
  73. }
  74. }
  75. }
  76. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/876063
推荐阅读
相关标签
  

闽ICP备14008679号