【C语言】红黑树

红黑树

1.二叉查找树

首先要了解的是二叉查找树,也称为二叉排序树,优点是在节点均匀分布的情况下,查找效率更高,缺点是,如果节点分布在一侧,查找时间就会约等于数组从头到尾的去查找。

  • 二叉查找树的子树都是二叉查找树。
  • 左子树都小于根节点,右子树都大于根节点

2.平衡二叉查找树

其次,平衡二叉查找树,也称为AVL树,AVL是它的两个发明者的名字组成。它有一套插入,删除的平衡机制,让插入删除后使用相应的平衡算法,再次成为AVL树,这样可以让每次的最坏查找时间接近O(logn),缺点是用于平衡的开销太大。

  • AVL树的子树都是AVL树
  • 左右子树的高度差小于等于1

3.红黑树

红黑树(Red Black Tree)是一种 二叉查找树,它并不是严格意义上的平衡二叉树,因为它有自己的平衡规则,和平衡二叉树规则不一样。它的查找,插入,删除的时间复杂度都是O(logn),n是指树中元素的个数。因此它在查找,插入,删除的最坏情况下运行时间很好。

​ 为什么查找,插入,删除的复杂度都是O(logn),因为红黑树自己有一套规则,去保持红黑树插入删除后还是红黑树。红黑树的平衡次数,相对于普通平衡二叉树少,开销更小。

  • 结点是红色或黑色(一个节点要么是红色,要么是黑色)
  • 根结点是黑色
  • 所有叶子都是黑色。(叶子是NIL结点)
  • 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
  • 从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点。

红黑树用在哪些地方:hashmap,cfs,epoll,定时器,nginx中

使用红黑树,

​ 第一,主要是使用它的(key,value)属性,使用key可以去树上查找相应的value

​ 第二,它是一个二叉排序树,中序遍历是顺序的,可以查一个范围,例如比某个key小的有哪些

1.定义一颗红黑树

typedef int KEY_TYPE;
//定义红黑树节点
typedef struct _rbtree_node
{
	KEY_TYPE key;
	void *value;
	struct _rbtree_node *right;
	struct _rbtree_node *left;
	struct _rbtree_node *parent;
	unsigned char color;
} rbtree_node;

//定义红黑树
typedef struct _rbtree
{
    //红黑树的根
	rbtree_node *root;
    //红黑树叶子节点
	rbtree_node *nil;
} rbtree;

2. 红黑树旋转

红黑树的插入,删除,会导致不平衡,需要旋转和变色
在这里插入图片描述

2.1 左旋

这里仅仅是旋转,是因为不满足上述5条红黑树性质而进行的旋转。与平衡二叉树的旋转不一样。

因此,只需要考虑旋转点与它的父节点之间的左旋。

// T是树根节点,x是旋转轴节点的父节点
void rbtree_left_rotate(rbtree *T, rbtree_node *x)
{
	//y为旋转轴节点
	rbtree_node *y = x->right; 

	x->right = y->left;
	if (y->left != T->nil)
	{
		y->left->parent = x;
	}

	y->parent = x->parent; 
	if (x->parent == T->nil)
	{
		T->root = y;
	}
	else if (x == x->parent->left)
	{
		x->parent->left = y;
	}
	else
	{
		x->parent->right = y;
	}

	y->left = x;
	x->parent = y;
}

2.2 右旋

将左旋代码的x改为y,left改为right即可

推荐一个零声教育学习教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:链接

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于C语言实现的红黑树示例代码: ```c #include <stdio.h> #include <stdlib.h> #define RED 0 #define BLACK 1 typedef struct Node { int value; int color; struct Node* left; struct Node* right; struct Node* parent; } Node; Node* root; void insert(int value) { Node* node = (Node*) malloc(sizeof(Node)); node->value = value; node->color = RED; node->left = NULL; node->right = NULL; node->parent = NULL; Node* parent = NULL; Node* current = root; while (current != NULL) { parent = current; if (value < current->value) { current = current->left; } else { current = current->right; } } node->parent = parent; if (parent == NULL) { root = node; } else if (value < parent->value) { parent->left = node; } else { parent->right = node; } fixup(node); } void fixup(Node* node) { while (node->parent != NULL && node->parent->color == RED) { if (node->parent == node->parent->parent->left) { Node* uncle = node->parent->parent->right; if (uncle != NULL && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->right) { node = node->parent; rotate_left(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotate_right(node->parent->parent); } } else { Node* uncle = node->parent->parent->left; if (uncle != NULL && uncle->color == RED) { node->parent->color = BLACK; uncle->color = BLACK; node->parent->parent->color = RED; node = node->parent->parent; } else { if (node == node->parent->left) { node = node->parent; rotate_right(node); } node->parent->color = BLACK; node->parent->parent->color = RED; rotate_left(node->parent->parent); } } } root->color = BLACK; } void rotate_left(Node* node) { Node* right = node->right; node->right = right->left; if (right->left != NULL) { right->left->parent = node; } right->parent = node->parent; if (node->parent == NULL) { root = right; } else if (node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } right->left = node; node->parent = right; } void rotate_right(Node* node) { Node* left = node->left; node->left = left->right; if (left->right != NULL) { left->right->parent = node; } left->parent = node->parent; if (node->parent == NULL) { root = left; } else if (node == node->parent->left) { node->parent->left = left; } else { node->parent->right = left; } left->right = node; node->parent = left; } void inorder_traverse(Node* node) { if (node != NULL) { inorder_traverse(node->left); printf("%d ", node->value); inorder_traverse(node->right); } } int main() { insert(10); insert(20); insert(30); insert(15); insert(18); insert(25); printf("Inorder traversal of the tree: "); inorder_traverse(root); printf("\n"); return 0; } ``` 这个示例代码实现了红黑树的基本操作,包括插入、修正颜色、左旋和右旋。在主函数中插入了一些节点并进行了中序遍历输出,以验证红黑树的正确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值