了解红黑树的插入

    在本教程中,您将学习如何将新节点插入到红黑树中。此外,您还将找到使用C语言在红黑树上执行插入的示例。
    红黑树是一种自平衡二叉搜索树,其中每个节点都包含一个额外的位,用于表示该节点的颜色,红色还是黑色。
    插入新节点时,新节点始终作为红色节点插入。插入新节点后,如果树违反了红黑树的属性,则执行以下操作。

  1. 重新着色
  2. 旋转
1. 插入新节点的算法

    按照以下步骤将新元素插入到红黑树中:

  1. newNode为:
    在这里插入图片描述
  2. 让y为树叶(即NIL),x为树根。新节点将插入到下面的树中。
    在这里插入图片描述
  3. 检查树是否为空(即x是否为NIL)。如果是,则插入newNode作为根节点并将其着色为黑色。
  4. 否则,重复以下步骤,直到达到叶(NIL)。
    a. 比较newKey和rootKey。
    b. 如果newKey大于rootKey,则遍历右子树。
    c. 否则遍历左子树。
    在这里插入图片描述
  5. 将叶的父节点指定为newNode的父节点。
  6. 如果leafKey大于newKey,则将newNode设为左孩子。
  7. 否则,将newNode设为右孩子。
    在这里插入图片描述
  8. 将NULL赋给newNode的左和右子级。
  9. 将红色指定给newNode。
    在这里插入图片描述
  10. 调用InsertFix算法来维护红黑树的属性。
为什么在红黑树中新插入的节点总是红色的?

    这是因为插入红色节点不会违反红黑树的深度属性。
    将红色节点附加到红色节点,违反了规则,但解决此问题比解决因违反深度属性而引入的问题更容易。

2. 插入后保持红黑属性的算法

    如果newNode的插入违反了红黑树的属性,则该算法用于维护红黑树的属性。(下面算法的过程比较混乱,红黑树的插入调整可以分为3种情况,见参考文档[2])

  1. 执行以下操作,直到newNode的父节点p变为黑色。
  2. 如果p是newNode的祖父母gP的左子级,请执行以下操作。例如,如图所示,newNode为20,p为15,gP为21。
    第一种情况:
    a. 如果newNode的gP的右子级的颜色为红色,则将gP的子级的颜色设置为黑色,将gP的颜色设置为红色。
    在这里插入图片描述
    b. 将gP重新指定为newNode,继续计算。
    在这里插入图片描述
    第二种情况:
    c. (在继续执行此步骤之前,将检查while循环。如果不满足条件,则该循环将中断。)
    如果newNode是p的右子级,则将p指定给newNode。
    在这里插入图片描述
    d. 左旋转newNode。
    在这里插入图片描述
    第三种情况:
    e. (在继续此步骤之前,请检查while循环。如果不满足条件,则循环会中断。)
    将p的颜色设置为黑色,gP的颜色设置为红色。
    在这里插入图片描述
    f. 右旋转gP。
    在这里插入图片描述
  3. 否则,请执行以下操作。
    a. 如果newNode的gP的左子级的颜色是红色,则将gP的两个子级的颜色都设置为黑色,并将gP的颜色设置为红色。
    b. 将gP分配给newNode。
    c. 否则,如果newNode是p的左子级,则将p指定给newNode并右旋转newNode。
    d. 将p的颜色设置为黑色,gP的颜色设置为红色。
    e. 左旋转gP。
  4. (此步骤在退出while循环后执行。)
    把树根设为黑色。
    在这里插入图片描述
    最后树是这样的:
    在这里插入图片描述
3. C示例
// Implementing Red-Black Tree in C

#include <stdio.h>
#include <stdlib.h>

enum nodeColor {
    
    
  RED,
  BLACK
};

struct rbNode {
    
    
  int data, color;
  struct rbNode *link[2];
};

struct rbNode *root = NULL;

// Create a red-black tree
struct rbNode *createNode(int data) {
    
    
  struct rbNode *newnode;
  newnode = (struct rbNode *)malloc(sizeof(struct rbNode));
  newnode->data = data;
  newnode->color = RED;
  newnode->link[0] = newnode->link[1] = NULL;
  return newnode;
}

// Insert an node
void insertion(int data) {
    
    
  struct rbNode *stack[98], *ptr, *newnode, *xPtr, *yPtr;
  int dir[98], ht = 0, index;
  ptr = root;
  if (!root) {
    
    
    root = createNode(data);
    return;
  }

  stack[ht] = root;
  dir[ht++] = 0;
  while (ptr != NULL) {
    
    
    if (ptr->data == data) {
    
    
      printf("Duplicates Not Allowed!!\n");
      return;
    }
    index = (data - ptr->data) > 0 ? 1 : 0;
    stack[ht] = ptr;
    ptr = ptr->link[index];
    dir[ht++] = index;
  }
  stack[ht - 1]->link[index] = newnode = createNode(data);
  while ((ht >= 3) && (stack[ht - 1]->color == RED)) {
    
    
    if (dir[ht - 2] == 0) {
    
    
      yPtr = stack[ht - 2]->link[1];
      if (yPtr != NULL && yPtr->color == RED) {
    
    
        stack[ht - 2]->color = RED;
        stack[ht - 1]->color = yPtr->color = BLACK;
        ht = ht - 2;
      } else {
    
    
        if (dir[ht - 1] == 0) {
    
    
          yPtr = stack[ht - 1];
        } else {
    
    
          xPtr = stack[ht - 1];
          yPtr = xPtr->link[1];
          xPtr->link[1] = yPtr->link[0];
          yPtr->link[0] = xPtr;
          stack[ht - 2]->link[0] = yPtr;
        }
        xPtr = stack[ht - 2];
        xPtr->color = RED;
        yPtr->color = BLACK;
        xPtr->link[0] = yPtr->link[1];
        yPtr->link[1] = xPtr;
        if (xPtr == root) {
    
    
          root = yPtr;
        } else {
    
    
          stack[ht - 3]->link[dir[ht - 3]] = yPtr;
        }
        break;
      }
    } else {
    
    
      yPtr = stack[ht - 2]->link[0];
      if ((yPtr != NULL) && (yPtr->color == RED)) {
    
    
        stack[ht - 2]->color = RED;
        stack[ht - 1]->color = yPtr->color = BLACK;
        ht = ht - 2;
      } else {
    
    
        if (dir[ht - 1] == 1) {
    
    
          yPtr = stack[ht - 1];
        } else {
    
    
          xPtr = stack[ht - 1];
          yPtr = xPtr->link[0];
          xPtr->link[0] = yPtr->link[1];
          yPtr->link[1] = xPtr;
          stack[ht - 2]->link[1] = yPtr;
        }
        xPtr = stack[ht - 2];
        yPtr->color = BLACK;
        xPtr->color = RED;
        xPtr->link[1] = yPtr->link[0];
        yPtr->link[0] = xPtr;
        if (xPtr == root) {
    
    
          root = yPtr;
        } else {
    
    
          stack[ht - 3]->link[dir[ht - 3]] = yPtr;
        }
        break;
      }
    }
  }
  root->color = BLACK;
}

// Delete a node
void deletion(int data) {
    
    
  struct rbNode *stack[98], *ptr, *xPtr, *yPtr;
  struct rbNode *pPtr, *qPtr, *rPtr;
  int dir[98], ht = 0, diff, i;
  enum nodeColor color;

  if (!root) {
    
    
    printf("Tree not available\n");
    return;
  }

  ptr = root;
  while (ptr != NULL) {
    
    
    if ((data - ptr->data) == 0)
      break;
    diff = (data - ptr->data) > 0 ? 1 : 0;
    stack[ht] = ptr;
    dir[ht++] = diff;
    ptr = ptr->link[diff];
  }

  if (ptr->link[1] == NULL) {
    
    
    if ((ptr == root) && (ptr->link[0] == NULL)) {
    
    
      free(ptr);
      root = NULL;
    } else if (ptr == root) {
    
    
      root = ptr->link[0];
      free(ptr);
    } else {
    
    
      stack[ht - 1]->link[dir[ht - 1]] = ptr->link[0];
    }
  } else {
    
    
    xPtr = ptr->link[1];
    if (xPtr->link[0] == NULL) {
    
    
      xPtr->link[0] = ptr->link[0];
      color = xPtr->color;
      xPtr->color = ptr->color;
      ptr->color = color;

      if (ptr == root) {
    
    
        root = xPtr;
      } else {
    
    
        stack[ht - 1]->link[dir[ht - 1]] = xPtr;
      }

      dir[ht] = 1;
      stack[ht++] = xPtr;
    } else {
    
    
      i = ht++;
      while (1) {
    
    
        dir[ht] = 0;
        stack[ht++] = xPtr;
        yPtr = xPtr->link[0];
        if (!yPtr->link[0])
          break;
        xPtr = yPtr;
      }

      dir[i] = 1;
      stack[i] = yPtr;
      if (i > 0)
        stack[i - 1]->link[dir[i - 1]] = yPtr;

      yPtr->link[0] = ptr->link[0];

      xPtr->link[0] = yPtr->link[1];
      yPtr->link[1] = ptr->link[1];

      if (ptr == root) {
    
    
        root = yPtr;
      }

      color = yPtr->color;
      yPtr->color = ptr->color;
      ptr->color = color;
    }
  }

  if (ht < 1)
    return;

  if (ptr->color == BLACK) {
    
    
    while (1) {
    
    
      pPtr = stack[ht - 1]->link[dir[ht - 1]];
      if (pPtr && pPtr->color == RED) {
    
    
        pPtr->color = BLACK;
        break;
      }

      if (ht < 2)
        break;

      if (dir[ht - 2] == 0) {
    
    
        rPtr = stack[ht - 1]->link[1];

        if (!rPtr)
          break;

        if (rPtr->color == RED) {
    
    
          stack[ht - 1]->color = RED;
          rPtr->color = BLACK;
          stack[ht - 1]->link[1] = rPtr->link[0];
          rPtr->link[0] = stack[ht - 1];

          if (stack[ht - 1] == root) {
    
    
            root = rPtr;
          } else {
    
    
            stack[ht - 2]->link[dir[ht - 2]] = rPtr;
          }
          dir[ht] = 0;
          stack[ht] = stack[ht - 1];
          stack[ht - 1] = rPtr;
          ht++;

          rPtr = stack[ht - 1]->link[1];
        }

        if ((!rPtr->link[0] || rPtr->link[0]->color == BLACK) &&
          (!rPtr->link[1] || rPtr->link[1]->color == BLACK)) {
    
    
          rPtr->color = RED;
        } else {
    
    
          if (!rPtr->link[1] || rPtr->link[1]->color == BLACK) {
    
    
            qPtr = rPtr->link[0];
            rPtr->color = RED;
            qPtr->color = BLACK;
            rPtr->link[0] = qPtr->link[1];
            qPtr->link[1] = rPtr;
            rPtr = stack[ht - 1]->link[1] = qPtr;
          }
          rPtr->color = stack[ht - 1]->color;
          stack[ht - 1]->color = BLACK;
          rPtr->link[1]->color = BLACK;
          stack[ht - 1]->link[1] = rPtr->link[0];
          rPtr->link[0] = stack[ht - 1];
          if (stack[ht - 1] == root) {
    
    
            root = rPtr;
          } else {
    
    
            stack[ht - 2]->link[dir[ht - 2]] = rPtr;
          }
          break;
        }
      } else {
    
    
        rPtr = stack[ht - 1]->link[0];
        if (!rPtr)
          break;

        if (rPtr->color == RED) {
    
    
          stack[ht - 1]->color = RED;
          rPtr->color = BLACK;
          stack[ht - 1]->link[0] = rPtr->link[1];
          rPtr->link[1] = stack[ht - 1];

          if (stack[ht - 1] == root) {
    
    
            root = rPtr;
          } else {
    
    
            stack[ht - 2]->link[dir[ht - 2]] = rPtr;
          }
          dir[ht] = 1;
          stack[ht] = stack[ht - 1];
          stack[ht - 1] = rPtr;
          ht++;

          rPtr = stack[ht - 1]->link[0];
        }
        if ((!rPtr->link[0] || rPtr->link[0]->color == BLACK) &&
          (!rPtr->link[1] || rPtr->link[1]->color == BLACK)) {
    
    
          rPtr->color = RED;
        } else {
    
    
          if (!rPtr->link[0] || rPtr->link[0]->color == BLACK) {
    
    
            qPtr = rPtr->link[1];
            rPtr->color = RED;
            qPtr->color = BLACK;
            rPtr->link[1] = qPtr->link[0];
            qPtr->link[0] = rPtr;
            rPtr = stack[ht - 1]->link[0] = qPtr;
          }
          rPtr->color = stack[ht - 1]->color;
          stack[ht - 1]->color = BLACK;
          rPtr->link[0]->color = BLACK;
          stack[ht - 1]->link[0] = rPtr->link[1];
          rPtr->link[1] = stack[ht - 1];
          if (stack[ht - 1] == root) {
    
    
            root = rPtr;
          } else {
    
    
            stack[ht - 2]->link[dir[ht - 2]] = rPtr;
          }
          break;
        }
      }
      ht--;
    }
  }
}

// Print the inorder traversal of the tree
void inorderTraversal(struct rbNode *node) {
    
    
  if (node) {
    
    
    inorderTraversal(node->link[0]);
    printf("%d  ", node->data);
    inorderTraversal(node->link[1]);
  }
  return;
}

// Driver code
int main() {
    
    
  int ch, data;
  while (1) {
    
    
    printf("1. Insertion\t2. Deletion\n");
    printf("3. Traverse\t4. Exit");
    printf("\nEnter your choice:");
    scanf("%d", &ch);
    switch (ch) {
    
    
      case 1:
        printf("Enter the element to insert:");
        scanf("%d", &data);
        insertion(data);
        break;
      case 2:
        printf("Enter the element to delete:");
        scanf("%d", &data);
        deletion(data);
        break;
      case 3:
        inorderTraversal(root);
        printf("\n");
        break;
      case 4:
        exit(0);
      default:
        printf("Not available\n");
        break;
    }
    printf("\n");
  }
  return 0;
}
参考文档

[1]Parewa Labs Pvt. Ltd.Insertion in a Red-Black Tree[EB/OL].https://www.programiz.com/dsa/insertion-in-a-red-black-tree,2020-01-01.
[2]海纳.红黑树(一):插入[EB/OL].https://zhuanlan.zhihu.com/p/25358857,2017-02-26.

猜你喜欢

转载自blog.csdn.net/zsx0728/article/details/114477016