红黑树insert操作

一、红黑树的insert理论

  1. 当前树为空树时,插入的节点是根节点,即黑色
  2. 当前树非空时,插入节点为叶子节点,若插入的叶子节点为黑色,那每次插入都会破坏性质5。为了避免每次插入都要进行相应的旋转维持红黑树性质,插入的所有叶子节点都是红色。由于不能出现连续的红色节点,所以需要检查父节点的颜色。若父节点为黑色,则插入完成,否则出现连续的红色节点需要做相应的调整:

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

在这里插入图片描述
这样就保持了局部和原来一样的红黑树的性质,所以全局也是保持了性质,调整完成!!!


在这里插入图片描述
在情况3中,使用交换颜色和右旋转的方法,也会产生连续两个红色节点的问题

其实这种情况很好解决,把B和C旋转到一条线上,就可以使用情况2的方法解决了
在这里插入图片描述
插入情况总结:

  • 情况1中叔叔是红色,插入到叶子节点的左侧或右侧;需要把父亲和叔叔置为黑色,爷爷置为红色,当前node指向爷爷,然后接着向上调整祖先节点
  • 情况2中叔叔是黑色,插入到叶子节点的左侧;交换父亲和爷爷的颜色,然后以父亲为轴右旋转
  • 情况3中叔叔是黑色,插入到叶子节点的右侧;以父亲为轴进行左旋转,将父亲、爷爷、叶子节点掰到同一侧,然后用情况2的方式处理

二、insert代码实现

void insert(const T& val) {
	if (root_ == nullptr) {
		root_ = new Node(val);
		return;
	}
	Node* parent = nullptr;
	Node* cur = root_;
	while (cur != nullptr) {
		if (cur->data_ > val) {
			parent = cur;
			cur = cur->right_;
		}
		else if (cur->data_ < val) {
			parent = cur;
			cur = cur->right_;
		}
		else {
			return;
		}
	}
	// 设置当前节点的parent和color
	Node* node = new Node(val, parent, nullptr, nullptr, Color::RED);
	if (parent->data_ > val) {
		parent->left_ = node;
	}
	else {
		parent->right_ = node;
	}

	// 插入节点的父节点也是红色,则出现连续的红色,需要调整
	if (Color::RED == color(parent)) {
		fixAfterInsert(node);
	}
}

void fixAfterInsert(Node* node) {
	// 父节点的颜色是红色,当前节点也是红色,不断调整
	while (color(parent(node)) == Color::RED) {
		// 父节点是爷爷的左孩子,插入的节点node在左子树
		if (parent(node) == left(parent(parent(node)))) {
			// 父亲是爷爷的左孩子,叔叔是爷爷的右孩子
			Node* uncle = right(parent(parent(node)));
			// 情况1:叔叔是红色(无论在父亲左侧或右侧)
			if (Color::RED == color(uncle)) {
				// 因为叔叔和父亲原来都是RED,爷爷原来必然是BLACK,上两代互换颜色
				setColor(parent(node), Color::BLACK);
				setColor(uncle, Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				// 上两代互换颜色后,爷爷变成RED,由于爷爷以前是BLACK,也许爷爷的父亲是RED,现在爷爷变RED后,可能连续出现两个RED,需要继续向上调整
				node = parent(parent(node));
			}
			else {
				// 情况2/3:叔叔是BLACK
				// 先处理叔叔是BLACK,插到叶子节点右侧的情况3
				if (node == right(parent(node))) {
					// 让node指向父亲,以node为轴旋转后,node才能成为情况2中刚插入的节点,进而统一情况2、3
					node = parent(node);
					leftRotate(node);
				}
				// 统一成情况2,叔叔是BLACK,插到叶子节点左侧
				setColor(parent(node), Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				rightRotate(parent(parent(node)));
				// 情况2、3保证了局部没有出现连续的RED,且保证了修改的局部支路中黑色节点数量没变,即全局也没有改变
				// 情况1只是修改颜色,情况2、3最多旋转两次,至此红黑树调整完成
				break;
			}
		}
		else {
			// 父节点是爷爷的右孩子,插入的节点node在右子树
			// 父亲是爷爷的右孩子,叔叔是爷爷的左孩子
			Node* uncle = left(parent(parent(node)));
			// 情况1:叔叔是红色(无论在父亲左侧或右侧)
			if (Color::RED == color(uncle)) {
				// 因为叔叔和父亲原来都是RED,爷爷原来必然是BLACK,上两代互换颜色
				setColor(parent(node), Color::BLACK);
				setColor(uncle, Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				// 上两代互换颜色后,爷爷变成RED,由于爷爷以前是BLACK,也许爷爷的父亲是RED,现在爷爷变RED后,可能连续出现两个RED,需要继续向上调整
				node = parent(parent(node));
			}
			else {
				// 情况2/3:叔叔是BLACK
				// 先处理叔叔是BLACK,插到叶子节点左侧的情况3
				if (node == left(parent(node))) {
					// 让node指向父亲,以node为轴旋转后,node才能成为情况2中刚插入的节点,进而统一情况2、3
					node = parent(node);
					rightRotate(node);
				}
				// 统一成情况2,叔叔是BLACK,插到叶子节点右侧
				setColor(parent(node), Color::BLACK);
				setColor(parent(parent(node)), Color::RED);
				leftRotate(parent(parent(node)));
				// 情况2、3保证了局部没有出现连续的RED,且保证了修改的局部支路中黑色节点数量没变,即全局也没有改变
				// 情况1只是修改颜色,情况2、3最多旋转两次,至此红黑树调整完成
				break;
			}
		}
	}
	// 此处需要将root_置为黑色
	setColor(root_, Color::BLACK);
}

红黑树插入1…10的过程如下:

在这里插入图片描述
插入红色节点3,交换红色父亲2和黑色爷爷1的颜色后,以爷爷1为轴左旋转


在这里插入图片描述
叔叔为红色,将父亲和叔叔的颜色置为黑色,爷爷置为红色,当前节点node指向爷爷,继续向上调整


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


红黑树插入1…39的结果如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 红黑树有下面几种操作:1. 插入:在红黑树插入一个新的节点;2. 删除:从红黑树中删除一个节点;3. 查找:在红黑树中查找一个特定的节点;4. 遍历:遍历红黑树中的所有节点。使用C语言实现红黑树操作代码可以参考下面的示例:1. 插入:/* Insert a node into the Red-Black Tree */ void rb_insert(struct rb_node *node, struct rb_root *root) { struct rb_node *parent = NULL; struct rb_node **link = &root->rb_node; /* Find the place to insert the new node */ while (*link) { parent = *link; if (node->key < parent->key) link = &(*link)->rb_left; else link = &(*link)->rb_right; } /* Insert the new node into the tree */ node->rb_parent = parent; node->rb_left = node->rb_right = NULL; *link = node; /* Fix any violations of the Red-Black Tree properties */ rb_insert_fixup(node, root); }2. 删除:/* Delete a node from the Red-Black Tree */ void rb_delete(struct rb_node *node, struct rb_root *root) { struct rb_node *child, *parent; /* If the node to be deleted has two children, replace it with its successor */ if (node->rb_left && node->rb_right) { struct rb_node *successor = rb_successor(node); node->key = successor->key; node = successor; } /* Get a pointer to the node's parent and child */ parent = node->rb_parent; child = node->rb_left ? node->rb_left : node->rb_right; /* Remove the node from the tree */ if (child) child->rb_parent = parent; if (parent) { if (node == parent->rb_left) parent->rb_left = child; else parent->rb_right = child; } else root->rb_node = child; /* Fix any violations of the Red-Black Tree properties */ rb_delete_fixup(node, root); }3. 查找:/* Find a node in the Red-Black Tree */ struct rb_node *rb_search(int key, struct rb_root *root) { struct rb_node *node = root->rb_node; while (node) { if (key < node->key) node = node->rb_left; else if (key > node->key) node = node->rb_right; else return node; } return NULL; }4. 遍历:/* Traverse the Red-Black Tree in-order */ void rb_inorder_traverse(struct rb_node *node, void (*func)(struct rb_node *)) { if (!node) return; rb_inorder_traverse(node->rb_left, func); func(node); rb_inorder_traverse(node->rb_right, func); } ### 回答2: 红黑树是一种自平衡的二叉搜索树,它具有以下特点:节点要么是红色,要么是黑色;根节点是黑色;每个叶子节点(NIL节点,空节点)是黑色;如果一个节点是红色,则它的两个子节点都是黑色;对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数量的黑色节点。 以下是使用C语言实现红黑树的所有操作代码: ```c #include <stdio.h> #include <stdlib.h> enum Color {RED, BLACK}; typedef struct Node { int data; enum Color color; struct Node *left, *right, *parent; } Node; Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->color = RED; newNode->left = newNode->right = newNode->parent = NULL; return newNode; } Node* bstInsert(Node* root, Node* newNode) { if (root == NULL) return newNode; if (newNode->data < root->data) { root->left = bstInsert(root->left, newNode); root->left->parent = root; } else if (newNode->data > root->data) { root->right = bstInsert(root->right, newNode); root->right->parent = root; } return root; } void swapColors(Node* a, Node* b) { enum Color temp; temp = a->color; a->color = b->color; b->color = temp; } void rotateLeft(Node** root, Node* x) { Node* y = x->right; x->right = y->left; if (y->left != NULL) y->left->parent = x; y->parent = x->parent; if (x->parent == NULL) *root = y; else if (x == x->parent->left) x->parent->left = y; else x->parent->right = y; y->left = x; x->parent = y; } void rotateRight(Node** root, Node* x) { Node* y = x->left; x->left = y->right; if (y->right != NULL) y->right->parent = x; y->parent = x->parent; if (x->parent == NULL) *root = y; else if (x == x->parent->right) x->parent->right = y; else x->parent->left = y; y->right = x; x->parent = y; } void fixViolation(Node** root, Node* newNode) { Node* parent = NULL; Node* grandParent = NULL; while ((newNode != *root) && (newNode->color != BLACK) && (newNode->parent->color == RED)) { parent = newNode->parent; grandParent = newNode->parent->parent; if (parent == grandParent->left) { Node* uncle = grandParent->right; if (uncle != NULL && uncle->color == RED) { grandParent->color = RED; parent->color = BLACK; uncle->color = BLACK; newNode = grandParent; } else { if (newNode == parent->right) { rotateLeft(root, parent); newNode = parent; parent = newNode->parent; } rotateRight(root, grandParent); swapColors(parent, grandParent); newNode = parent; } } else { Node* uncle = grandParent->left; if ((uncle != NULL) && (uncle->color == RED)) { grandParent->color = RED; parent->color = BLACK; uncle->color = BLACK; newNode = grandParent; } else { if (newNode == parent->left) { rotateRight(root, parent); newNode = parent; parent = newNode->parent; } rotateLeft(root, grandParent); swapColors(parent, grandParent); newNode = parent; } } } (*root)->color = BLACK; } Node* insertNode(Node* root, int data) { Node* newNode = createNode(data); root = bstInsert(root, newNode); fixViolation(&root, newNode); return root; } void inOrderTraversal(Node* root) { if (root == NULL) return; inOrderTraversal(root->left); printf("%d ", root->data); inOrderTraversal(root->right); } int main() { Node* root = NULL; root = insertNode(root, 10); root = insertNode(root, 20); root = insertNode(root, 30); root = insertNode(root, 40); root = insertNode(root, 50); root = insertNode(root, 60); printf("In-order traversal of the constructed Red-Black tree is: "); inOrderTraversal(root); return 0; } ``` 上述代码实现了红黑树插入操作,并进行了适当的旋转和颜色交换以保证红黑树的特性。在主函数中,将节点插入红黑树中,并进行中序遍历输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bugcoder-9905

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值