红黑树:自平衡的二叉搜索树

当我们向红黑树中插入一个新节点时,首先将其插入为一个红色节点,然后通过一系列的旋转和变色操作来调整树的结构,以保持红黑树的性质。

下面是红黑树中插入节点时可能出现的情况以及相应的操作:

当插入的节点是树的根节点时,我们将其标记为黑色,即满足性质2。
当插入的节点的父节点是黑色时,我们无需进行任何调整,因为不会破坏红黑树的性质。
当插入的节点的父节点是红色时,此时可能破坏了性质4,即一个红色节点的子节点不能是红色。为了修复这个问题,我们需要进行一些旋转和变色的操作。
以下是修复红黑树插入节点时破坏性质4的情况和相应的操作:

情况1:叔叔节点是红色(父节点的兄弟节点)
解决方案:将父节点和叔叔节点都变为黑色,将祖父节点变为红色,然后将当前节点指向祖父节点,并以祖父节点为基准进行进一步调整。这样可以保持性质5。

情况2:叔叔节点是黑色,当前节点是父节点的右子节点
解决方案:将当前节点设置为其父节点,并以新的当前节点为基准进行左旋转,转化为情况3。

情况3:叔叔节点是黑色,当前节点是父节点的左子节点
解决方案:将父节点设为黑色,祖父节点设为红色,然后以祖父节点为基准进行右旋转。这样可以保持性质5。

通过以上操作,我们可以保持红黑树的性质,并且在最坏情况下,红黑树的高度仍然保持在O(log n)的范围内,保证了高效的插入和搜索操作。

在给出的JavaScript示例中,我们实现了红黑树的插入操作。首先,我们定义了一个Node类来表示树中的节点,每个节点包含键、值、颜色以及左右子节点和父节点的引用。然后,我们定义了RedBlackTree类,其中包含了插入节点和修复违规的方法。

在插入节点的方法中,我们首先判断树是否为空,如果为空,则将新节点作为根节点。否则,我们调用insertNode方法来递归地插入节点到正确的位置。插入完成后,我们调用fixViolation方法来修复违规,确保红黑树的性质得到保持。

在fixViolation方法中,我们使用while循环来处理可能出现的违规情况。根据当前节点的父节点、祖父节点以及叔叔节点的颜色,我们执行相应的旋转和变色操作来修复违规。

最后,给出了一个使用示例,通过插入一些节点来构建红黑树。你可以根据需要扩展该示例,添加其他方法如删除节点、搜索节点等。

class Node {
    
    
  constructor(key, value, color) {
    
    
    this.key = key;
    this.value = value;
    this.color = color;
    this.left = null;
    this.right = null;
    this.parent = null;
  }
}

class RedBlackTree {
    
    
  constructor() {
    
    
    this.root = null;
  }

  insert(key, value) {
    
    
    const newNode = new Node(key, value, "red");
    if (this.root === null) {
    
    
      this.root = newNode;
    } else {
    
    
      this.insertNode(this.root, newNode);
    }
    this.fixViolation(newNode);
  }

  insertNode(root, newNode) {
    
    
    if (newNode.key < root.key) {
    
    
      if (root.left === null) {
    
    
        root.left = newNode;
        newNode.parent = root;
      } else {
    
    
        this.insertNode(root.left, newNode);
      }
    } else if (newNode.key > root.key) {
    
    
      if (root.right === null) {
    
    
        root.right = newNode;
        newNode.parent = root;
      } else {
    
    
        this.insertNode(root.right, newNode);
      }
    }
  }

  fixViolation(node) {
    
    
    while (
      node !== this.root &&
      node.color === "red" &&
      node.parent.color === "red"
    ) {
    
    
      const parent = node.parent;
      const grandParent = parent.parent;

      if (parent === grandParent.left) {
    
    
        const uncle = grandParent.right;

        if (uncle !== null && uncle.color === "red") {
    
    
          grandParent.color = "red";
          parent.color = "black";
          uncle.color = "black";
          node = grandParent;
        } else {
    
    
          if (node === parent.right) {
    
    
            this.rotateLeft(parent);
            node = parent;
            parent = node.parent;
          }

          parent.color = "black";
          grandParent.color = "red";
          this.rotateRight(grandParent);
        }
      } else {
    
    
        const uncle = grandParent.left;

        if (uncle !== null && uncle.color === "red") {
    
    
          grandParent.color = "red";
          parent.color = "black";
          uncle.color = "black";
          node = grandParent;
        } else {
    
    
          if (node === parent.left) {
    
    
            this.rotateRight(parent);
            node = parent;
            parent = node.parent;
          }

          parent.color = "black";
          grandParent.color = "red";
          this.rotateLeft(grandParent);
        }
      }
    }

    this.root.color = "black";
  }

  rotateLeft(node) {
    
    
    const rightChild = node.right;
    node.right = rightChild.left;

    if (rightChild.left !== null) {
    
    
      rightChild.left.parent = node;
    }

    rightChild.parent = node.parent;

    if (node.parent === null) {
    
    
      this.root = rightChild;
    } else if (node === node.parent.left) {
    
    
      node.parent.left = rightChild;
    } else {
    
    
      node.parent.right = rightChild;
    }

    rightChild.left = node;
    node.parent = rightChild;
  }

  rotateRight(node) {
    
    
    const leftChild = node.left;
    node.left = leftChild.right;

    if (leftChild.right !== null) {
    
    
      leftChild.right.parent = node;
    }

    leftChild.parent = node.parent;

    if (node.parent === null) {
    
    
      this.root = leftChild;
    } else if (node === node.parent.left) {
    
    
      node.parent.left = leftChild;
    } else {
    
    
      node.parent.right = leftChild;
    }

    leftChild.right = node;
    node.parent = leftChild;
  }

  // 其他方法,如删除节点等
}

// 使用示例
const tree = new RedBlackTree();
tree.insert(10, "value1");
tree.insert(20, "value2");
tree.insert(30, "value3");
tree.insert(15, "value4");
tree.insert(25, "value5");

上述代码实现了红黑树的插入操作,并通过一系列的旋转和变色操作来保持树的平衡。你可以根据需要添加其他方法,如删除节点等。

猜你喜欢

转载自blog.csdn.net/qq_29669259/article/details/130965118
今日推荐