📜  红黑树|套装3(删除)

📅  最后修改于: 2021-04-17 10:56:44             🧑  作者: Mango

在之前的文章中,我们已经讨论了关于红黑树的以下主题。我们强烈建议将以下帖子作为此帖子的先决条件。
红黑树介绍
红黑树插入
插入与删除:
像“插入”一样,重新着色和旋转可用于保持“红黑”属性。
在插入操作中,我们检查叔叔的颜色,以决定适当的情况。在删除操作中,我们检查兄弟姐妹的颜色以决定适当的情况。
插入后违反的主要属性是两个连续的红色。在delete中,主要违反的属性是,子树中黑色高度的更改,因为删除黑色节点可能会导致根到叶路径的黑色高度降低。
删除是一个相当复杂的过程。为了理解删除,使用了双重黑色的概念。当删除黑色节点并用黑色子节点替换时,该子节点被标记为double black 。现在的主要任务是将这种双黑色转换为单黑色。
删除步骤
以下是删除的详细步骤。
1)执行标准的BST删除。当我们在BST中执行标准删除操作时,我们总是最终删除一个要么是叶子要么只有一个孩子的节点(对于内部节点,我们复制后继节点,然后递归调用delete作为后继节点,后继节点始终是叶节点或一个有一个孩子的节点)。因此,我们只需要处理一个节点为叶子或有一个孩子的情况。令v为要删除的节点,让u为替换v的子节点(请注意,当v为叶子且u的颜色被视为Black时,u为NULL)。
2)简单案例:如果u或v为红色,我们会将替换后的子级标记为黑色(黑色高度不变)。请注意,u和v都不能为红色,因为v是u的父级,并且红黑树中不允许两个连续的红色。

rbdelete11

3)如果u和v均为Black
3.1)将您的颜色涂成双黑色。现在,我们的任务减少了将这种双重黑色转换为单一黑色的过程。请注意,如果v是叶子,则u为NULL,并且NULL的颜色被视为黑色。因此,删除黑叶也将导致双黑。

rbdelete12_new

3.2)在当前节点u为双黑且不是根节点的情况下执行以下操作。令node的同级为s
…。 (a):如果兄弟姐妹s是黑色,并且兄弟姐妹的至少一个孩子是红色,则进行轮换。让s的红色孩子成为r 。根据s和r的位置,可以将这种情况分为四个子情况。
………….. (i) Left Left Case(s是其父项的左子代,r是s的左子代,或s的两个子代均为红色)。这是下图所示的右对右镜像。
………….. (ii)左右案例(s是其父代的左子代,r是右子代)。这是下图所示的左右案例的镜像。
………….. (iii)正确的权利案例(s是其父母的正确子女,r是s的正确子女,或s的两个子女均为红色)

rbdelete13新

………….. (iv)右左个案(s是其父代的右子,r是s的左子)

rbdelete14

….. (b):如果同级是黑色,并且其两个子级都是黑色,则对父级执行重新着色,如果父级是黑色,则对父级进行递归。

rbdelete15

在这种情况下,如果父对象为红色,则无需为父对象重复,我们可以简单地将其设为黑色(红色+双黑色=单个黑色)。
….. (c):如果兄弟姐妹为红色,请旋转以将旧兄弟姐妹向上移动,为旧兄弟姐妹和父级重新着色。新的兄弟姐妹始终为黑色(请参见下图)。这主要是通过旋转将树转换为黑色同级格,并导致情况(a)或(b)。这种情况可以分为两个子情况。
………….. (i)左例(s是其父项的左子)。这是下图所示的右对右镜像。我们右旋转父级p。
………….. (iii)权利个案(s是其父母的正直子女)。我们左旋转父级p。

rbdelete16

3.3)如果u为根,则将其设为黑色,然后返回(完整树的黑色高度减少1)。
下面是上述方法的C++实现:

CPP
#include 
#include 
using namespace std;
 
enum COLOR { RED, BLACK };
 
class Node {
public:
  int val;
  COLOR color;
  Node *left, *right, *parent;
 
  Node(int val) : val(val) {
    parent = left = right = NULL;
 
    // Node is created during insertion
    // Node is red at insertion
    color = RED;
  }
 
  // returns pointer to uncle
  Node *uncle() {
    // If no parent or grandparent, then no uncle
    if (parent == NULL or parent->parent == NULL)
      return NULL;
 
    if (parent->isOnLeft())
      // uncle on right
      return parent->parent->right;
    else
      // uncle on left
      return parent->parent->left;
  }
 
  // check if node is left child of parent
  bool isOnLeft() { return this == parent->left; }
 
  // returns pointer to sibling
  Node *sibling() {
    // sibling null if no parent
    if (parent == NULL)
      return NULL;
 
    if (isOnLeft())
      return parent->right;
 
    return parent->left;
  }
 
  // moves node down and moves given node in its place
  void moveDown(Node *nParent) {
    if (parent != NULL) {
      if (isOnLeft()) {
        parent->left = nParent;
      } else {
        parent->right = nParent;
      }
    }
    nParent->parent = parent;
    parent = nParent;
  }
 
  bool hasRedChild() {
    return (left != NULL and left->color == RED) or
           (right != NULL and right->color == RED);
  }
};
 
class RBTree {
  Node *root;
 
  // left rotates the given node
  void leftRotate(Node *x) {
    // new parent will be node's right child
    Node *nParent = x->right;
 
    // update root if current node is root
    if (x == root)
      root = nParent;
 
    x->moveDown(nParent);
 
    // connect x with new parent's left element
    x->right = nParent->left;
    // connect new parent's left element with node
    // if it is not null
    if (nParent->left != NULL)
      nParent->left->parent = x;
 
    // connect new parent with x
    nParent->left = x;
  }
 
  void rightRotate(Node *x) {
    // new parent will be node's left child
    Node *nParent = x->left;
 
    // update root if current node is root
    if (x == root)
      root = nParent;
 
    x->moveDown(nParent);
 
    // connect x with new parent's right element
    x->left = nParent->right;
    // connect new parent's right element with node
    // if it is not null
    if (nParent->right != NULL)
      nParent->right->parent = x;
 
    // connect new parent with x
    nParent->right = x;
  }
 
  void swapColors(Node *x1, Node *x2) {
    COLOR temp;
    temp = x1->color;
    x1->color = x2->color;
    x2->color = temp;
  }
 
  void swapValues(Node *u, Node *v) {
    int temp;
    temp = u->val;
    u->val = v->val;
    v->val = temp;
  }
 
  // fix red red at given node
  void fixRedRed(Node *x) {
    // if x is root color it black and return
    if (x == root) {
      x->color = BLACK;
      return;
    }
 
    // initialize parent, grandparent, uncle
    Node *parent = x->parent, *grandparent = parent->parent,
         *uncle = x->uncle();
 
    if (parent->color != BLACK) {
      if (uncle != NULL && uncle->color == RED) {
        // uncle red, perform recoloring and recurse
        parent->color = BLACK;
        uncle->color = BLACK;
        grandparent->color = RED;
        fixRedRed(grandparent);
      } else {
        // Else perform LR, LL, RL, RR
        if (parent->isOnLeft()) {
          if (x->isOnLeft()) {
            // for left right
            swapColors(parent, grandparent);
          } else {
            leftRotate(parent);
            swapColors(x, grandparent);
          }
          // for left left and left right
          rightRotate(grandparent);
        } else {
          if (x->isOnLeft()) {
            // for right left
            rightRotate(parent);
            swapColors(x, grandparent);
          } else {
            swapColors(parent, grandparent);
          }
 
          // for right right and right left
          leftRotate(grandparent);
        }
      }
    }
  }
 
  // find node that do not have a left child
  // in the subtree of the given node
  Node *successor(Node *x) {
    Node *temp = x;
 
    while (temp->left != NULL)
      temp = temp->left;
 
    return temp;
  }
 
  // find node that replaces a deleted node in BST
  Node *BSTreplace(Node *x) {
    // when node have 2 children
    if (x->left != NULL and x->right != NULL)
      return successor(x->right);
 
    // when leaf
    if (x->left == NULL and x->right == NULL)
      return NULL;
 
    // when single child
    if (x->left != NULL)
      return x->left;
    else
      return x->right;
  }
 
  // deletes the given node
  void deleteNode(Node *v) {
    Node *u = BSTreplace(v);
 
    // True when u and v are both black
    bool uvBlack = ((u == NULL or u->color == BLACK) and (v->color == BLACK));
    Node *parent = v->parent;
 
    if (u == NULL) {
      // u is NULL therefore v is leaf
      if (v == root) {
        // v is root, making root null
        root = NULL;
      } else {
        if (uvBlack) {
          // u and v both black
          // v is leaf, fix double black at v
          fixDoubleBlack(v);
        } else {
          // u or v is red
          if (v->sibling() != NULL)
            // sibling is not null, make it red"
            v->sibling()->color = RED;
        }
 
        // delete v from the tree
        if (v->isOnLeft()) {
          parent->left = NULL;
        } else {
          parent->right = NULL;
        }
      }
      delete v;
      return;
    }
 
    if (v->left == NULL or v->right == NULL) {
      // v has 1 child
      if (v == root) {
        // v is root, assign the value of u to v, and delete u
        v->val = u->val;
        v->left = v->right = NULL;
        delete u;
      } else {
        // Detach v from tree and move u up
        if (v->isOnLeft()) {
          parent->left = u;
        } else {
          parent->right = u;
        }
        delete v;
        u->parent = parent;
        if (uvBlack) {
          // u and v both black, fix double black at u
          fixDoubleBlack(u);
        } else {
          // u or v red, color u black
          u->color = BLACK;
        }
      }
      return;
    }
 
    // v has 2 children, swap values with successor and recurse
    swapValues(u, v);
    deleteNode(u);
  }
 
  void fixDoubleBlack(Node *x) {
    if (x == root)
      // Reached root
      return;
 
    Node *sibling = x->sibling(), *parent = x->parent;
    if (sibling == NULL) {
      // No sibiling, double black pushed up
      fixDoubleBlack(parent);
    } else {
      if (sibling->color == RED) {
        // Sibling red
        parent->color = RED;
        sibling->color = BLACK;
        if (sibling->isOnLeft()) {
          // left case
          rightRotate(parent);
        } else {
          // right case
          leftRotate(parent);
        }
        fixDoubleBlack(x);
      } else {
        // Sibling black
        if (sibling->hasRedChild()) {
          // at least 1 red children
          if (sibling->left != NULL and sibling->left->color == RED) {
            if (sibling->isOnLeft()) {
              // left left
              sibling->left->color = sibling->color;
              sibling->color = parent->color;
              rightRotate(parent);
            } else {
              // right left
              sibling->left->color = parent->color;
              rightRotate(sibling);
              leftRotate(parent);
            }
          } else {
            if (sibling->isOnLeft()) {
              // left right
              sibling->right->color = parent->color;
              leftRotate(sibling);
              rightRotate(parent);
            } else {
              // right right
              sibling->right->color = sibling->color;
              sibling->color = parent->color;
              leftRotate(parent);
            }
          }
          parent->color = BLACK;
        } else {
          // 2 black children
          sibling->color = RED;
          if (parent->color == BLACK)
            fixDoubleBlack(parent);
          else
            parent->color = BLACK;
        }
      }
    }
  }
 
  // prints level order for given node
  void levelOrder(Node *x) {
    if (x == NULL)
      // return if node is null
      return;
 
    // queue for level order
    queue q;
    Node *curr;
 
    // push x
    q.push(x);
 
    while (!q.empty()) {
      // while q is not empty
      // dequeue
      curr = q.front();
      q.pop();
 
      // print node value
      cout << curr->val << " ";
 
      // push children to queue
      if (curr->left != NULL)
        q.push(curr->left);
      if (curr->right != NULL)
        q.push(curr->right);
    }
  }
 
  // prints inorder recursively
  void inorder(Node *x) {
    if (x == NULL)
      return;
    inorder(x->left);
    cout << x->val << " ";
    inorder(x->right);
  }
 
public:
  // constructor
  // initialize root
  RBTree() { root = NULL; }
 
  Node *getRoot() { return root; }
 
  // searches for given value
  // if found returns the node (used for delete)
  // else returns the last node while traversing (used in insert)
  Node *search(int n) {
    Node *temp = root;
    while (temp != NULL) {
      if (n < temp->val) {
        if (temp->left == NULL)
          break;
        else
          temp = temp->left;
      } else if (n == temp->val) {
        break;
      } else {
        if (temp->right == NULL)
          break;
        else
          temp = temp->right;
      }
    }
 
    return temp;
  }
 
  // inserts the given value to tree
  void insert(int n) {
    Node *newNode = new Node(n);
    if (root == NULL) {
      // when root is null
      // simply insert value at root
      newNode->color = BLACK;
      root = newNode;
    } else {
      Node *temp = search(n);
 
      if (temp->val == n) {
        // return if value already exists
        return;
      }
 
      // if value is not found, search returns the node
      // where the value is to be inserted
 
      // connect new node to correct node
      newNode->parent = temp;
 
      if (n < temp->val)
        temp->left = newNode;
      else
        temp->right = newNode;
 
      // fix red red voilaton if exists
      fixRedRed(newNode);
    }
  }
 
  // utility function that deletes the node with given value
  void deleteByVal(int n) {
    if (root == NULL)
      // Tree is empty
      return;
 
    Node *v = search(n), *u;
 
    if (v->val != n) {
      cout << "No node found to delete with value:" << n << endl;
      return;
    }
 
    deleteNode(v);
  }
 
  // prints inorder of the tree
  void printInOrder() {
    cout << "Inorder: " << endl;
    if (root == NULL)
      cout << "Tree is empty" << endl;
    else
      inorder(root);
    cout << endl;
  }
 
  // prints level order of the tree
  void printLevelOrder() {
    cout << "Level order: " << endl;
    if (root == NULL)
      cout << "Tree is empty" << endl;
    else
      levelOrder(root);
    cout << endl;
  }
};
 
int main() {
  RBTree tree;
 
  tree.insert(7);
  tree.insert(3);
  tree.insert(18);
  tree.insert(10);
  tree.insert(22);
  tree.insert(8);
  tree.insert(11);
  tree.insert(26);
  tree.insert(2);
  tree.insert(6);
  tree.insert(13);
 
  tree.printInOrder();
  tree.printLevelOrder();
 
  cout<


输出:

Inorder: 
2 3 6 7 8 10 11 13 18 22 26 
Level order: 
10 7 18 3 8 11 22 2 6 13 26 

Deleting 18, 11, 3, 10, 22
Inorder: 
2 6 7 8 13 26 
Level order: 
13 7 26 6 8 2