红黑二叉树(附写的源码)

简单讲一下B树B+树

这些树的作用,主要都体现于增删改查。

而为了性能的增强,从二叉树开始一步步进化,有了有序二叉树,然后到平衡二叉树,然后到了23树。

但23树依然不太优越。

假如有1w的数据,那么23树的层数就会很多,层数越多,增删改查消耗的时间也就越多。

如果我们希望它能够在数据量多的时候,层数少,那么就是每一层能够保存更多的数据,这样子虽然查找快了一些,但每一层又臃肿了一些。

不同的数据结构各有优越,要考虑不同情况使用不同的数据结构

B树(B_ B-)

在23树的基础上引入M值的概念,M值是变化的,相对23树而言更加灵活。

简单举例:23树就是M值为3的B树。

如图,B树和23树的原理一样,B的M为4,即表示到达4个分裂:

B+树

B树加上2个特性。

  1. 数据只存在叶子节点上
  2. 叶子节点之间用指针连接

 

  1. 这样之后,nb的就是第二个特性(叶子节点之间用指针连接):

做链表一样,而上面的6和73是索引。

比如要找14,链表的话是一个一个找过去。

而这个通过索引6和73,直接找到大致区间进行搜索。

平衡二叉树优化,为红黑二叉树

        在不怎么降低AVL查找效率的情况下,大幅度优化增删效率。

红黑二叉树相对AVL树:稍微降低查找效率(不是绝对平衡),增删效率加快很多(3次旋转可以搞定

红黑二叉树规则

  1. 树中节点 非红即黑
  2. 根和叶子都是黑节点(空节点算黑节点),枝干非红即黑
  3. 红色节点的孩子必定是黑色
  4. 从一个节点到这个节点的任意一个子孙节点,路径上包含相同个数的黑色节点

如图:

红黑二叉树插入步骤:

  1. 新节点统一着色为红色

情况一:新节点为根节点,着色为黑

情况二:新节点的父节点颜色为黑,啥都不干

情况三:新节点的父节点颜色为红:

3.1被插入节点父节点颜色为红色,并且叔叔节点颜色为黑色,并且插入节点是其父节点的左孩子

怎么做:3.1.1父节点设置为黑色

3.1.2爷爷节点设置为红色

3.1.3以其父节点为轴右旋

3.2被插入节点父节点颜色为红色,并且叔叔节点颜色为黑色,并且插入节点是其父节点的右孩子

怎么做:3.2.1以其父节点为轴左旋

3.2.2新节点设置为黑色

3.3被插入节点父节点颜色为红色,并且叔叔节点颜色为红色

怎么做:3.3.1父节点设置为黑色

3.3.2叔叔节点设置为黑色

3.3.3爷爷节点设置为红色

3.3.4把爷爷节点当成新节点插入

代码如下:

#include <stdio.h>
#include <stdlib.h>			
//辅助宏
#define RED		0
#define BLACK	1
//获取节点的颜色
#define COLOR(x)  ((x)->color)
//获取当前节点的父节点
#define PARENTNODE(x) ((x)->parentNode)
//设置当前节点的父节点
#define SET_PARENT(x,p) ((x)->parentNode=(p))
//设置当前节点的颜色
#define SET_COLOR(x,c) ((x)->color=(c))
//设置当前节点颜色为黑色
#define SET_BLACK(x) ((x)->color=BLACK)
//设置当前节点颜色为红色
#define SET_RED(x) ((x)->color=RED)
//判断当前节点颜色是否为黑色
#define IS_BLACK(x) ((x)->color==BLACK)
//判断当前节点颜色是否为红色
#define IS_RED(x) ((x)->color==RED)
//红黑树的结构体
struct RBTreeNode
{
	unsigned int color;			//颜色
	int key;				//关键字
	struct RBTreeNode* LChild;
	struct RBTreeNode* RChild;
	struct RBTreeNode* parentNode;
}
typedef; struct RBTreeNode	NODE;
typedef  struct RBTreeNode* LPNODE;

struct RBTree
{
	LPNODE 	root;
	int 	treeSize;
}
typedef; struct RBTree	RBTREE;
typedef struct RBTree* LPRBTREE;

LPNODE createNode(int key)
{
	LPNODE newNode = (LPNODE)malloc(sizeof(NODE));
	newNode->key = key;
	newNode->LChild = NULL;
	newNode->RChild = NULL;
	newNode->parentNode = NULL;
	newNode->color = BLACK;
	return newNode;
}
//创建树
LPRBTREE createRBTree()
{
	LPRBTREE tree = (LPRBTREE)malloc(sizeof(RBTREE));
	tree->root = NULL;
	return tree;
}
//左旋
void L_Rotation(LPRBTREE tree, LPNODE x)
{
	//1.拿到x的右边 y怎么表示?
	LPNODE y = x->RChild;
	//2.y的左边成为x的右边
	x->RChild = y->LChild;
	//3.判断下y的左边是不是空的
	//父节点的处理
	if (y->LChild != NULL) {
		y->LChild->parentNode = x;
	}
	//y替换了x ,所以x的父节点就是y的父节点
	y->parentNode = x->parentNode;
	//如果x是根不,循环后,红黑树的根改变
	if (x->parentNode == NULL) {
		tree->root = y;
	}
	else {
		//不是根部判断x是在原来父节点左边还是右边
		if (x->parentNode->LChild == x) {
			x->parentNode->LChild = y;
		}
		else {
			x->parentNode->RChild = y;
		}
	}
	//处理一下x的位置
	y->LChild = x;
	x->parentNode = y;
}
//右旋
void R_Rotation(LPRBTREE tree, LPNODE y)
{
	//拿到x节点
	LPNODE x = y->LChild;
	y->LChild = x->RChild;
	if (x->RChild != NULL)
	{
		x->RChild->parentNode = y;
	}
	//处理x和y的父节点
	x->parentNode = y->parentNode;
	if (y->parentNode == NULL)
	{
		tree->root = x;
	}
	else
	{
		if (y == y->parentNode->LChild)
		{
			y->parentNode->LChild = x;
		}
		else
		{
			y->parentNode->RChild = x;
		}
	}
	//
	x->RChild = y;
	y->parentNode = x;
}
//1.插入
//1.1 当作BST(有序二叉树)做一个插入
//1.2 调整成为红黑树
void insertAdjustTree(LPRBTREE tree, LPNODE node)
{
	LPNODE parent, gparent;
	while ((parent = PARENTNODE(node)) && IS_RED(parent))
	{
		gparent = PARENTNODE(parent);
		//三种情况分析
		if (parent == gparent->LChild)
		{//父节点是祖父节点的左孩子
			//No.1 U=RED;//对应笔记中的情况三 . 3
			{
				LPNODE uncle = gparent->RChild;
				if (uncle && IS_RED(uncle))
				{
					SET_BLACK(uncle);		 //uncle->color=BLACK;
					SET_BLACK(parent);		 //parent->color=BLACK;
					SET_RED(gparent);	     //gpranet->color=RED;
					node = gparent;
					continue;
				}
			}
			//No.2 u=BLACK S=R //对应笔记中 情况三.1
			if (parent->RChild == node)
			{
				LPNODE temp;
				L_Rotation(tree, parent);
				temp = parent;
				parent = node;
				node = temp;
			}
			//No.3 U=BLACK S=L    //对应笔记中 情况三.2
			SET_BLACK(parent);
			SET_RED(gparent);
			R_Rotation(tree, gparent);
		}
		else
		{//父节点是祖父节点的右孩子
			//No.1   //对应笔记中的情况三 . 3
			{
				LPNODE uncle = gparent->LChild;
				if (uncle && IS_RED(uncle))
				{
					SET_BLACK(uncle);		 //uncle->color=BLACK;
					SET_BLACK(parent);		 //parent->color=BLACK;
					SET_RED(gparent);	     //gpranet->color=RED;
					node = gparent;
					continue;
				}
			}
			//No.2  
			if (parent->LChild == node) //对应笔记中 情况三.1
			{
				LPNODE temp;
				R_Rotation(tree, parent);
				temp = parent;
				parent = node;
				node = temp;
			}
			SET_BLACK(parent);//对应笔记中 情况三.2
			SET_RED(gparent);
			L_Rotation(tree, gparent);
		}
	}
	SET_BLACK(tree->root);// 对应笔记中 情况一:新节点是根节点
}
//1.1 当作BST做一个插入
void insertNode(LPRBTREE tree, LPNODE node)
{
	//当作BST做一个插入
	LPNODE y = NULL;
	LPNODE x = tree->root;
	while (x != NULL)
	{
		y = x;		//记录父节点
		if (node->key < x->key)
		{
			x = x->LChild;
		}
		else
		{
			x = x->RChild;
		}
	}
	//新节点应该插在y节点的下面
	SET_PARENT(node, y);
	if (y != NULL)
	{
		if (node->key < y->key)
		{
			y->LChild = node;
		}
		else
		{
			y->RChild = node;
		}
	}
	else	//树是空的,第一次插入节点就要成为根节点
	{
		tree->root = node;
	}
	SET_COLOR(node, RED);		//插入节点着色红色
	//2.按照红黑树的规则情况去调整二叉树成为红黑树
	insertAdjustTree(tree, node);
}
void printCurNode(LPNODE curNode)
{
	printf("%d:%s\n", curNode->key, curNode->color ? "BLACK" : "RED");
}
void preOrder(LPNODE root)
{
	if (root != NULL)
	{
		printCurNode(root);	//printf("%d:%s\n", curNode->key, curNode->color ? "BLACK" : "RED");
		preOrder(root->LChild);
		preOrder(root->RChild);
	}
}
//2.红黑树的删除
//2.1 当做BST 去做删除
//2.2 调整
void deleteAdjustTree(LPRBTREE tree, LPNODE node, LPNODE parent)
{
	LPNODE other;
	while (!node || IS_BLACK(node) && node != tree->root)
	{
		if (parent->LChild == node) //node是其父节点的左孩子
		{
			other = parent->RChild;
			if (IS_RED(other))//node的兄弟为红色节点
			{
				//No.1 xB=RED
				SET_BLACK(other);
				SET_RED(parent);
				L_Rotation(tree, parent);
				other = parent->RChild;
			}
			if ((!other->LChild) || IS_BLACK(other->LChild) &&
				(!other->RChild) || IS_BLACK(other->RChild))
			{
				//No.2  xB=BLACK
				SET_RED(other);
				node = parent;
				parent = PARENTNODE(node);
			}
			else
			{
				if (!other->RChild || IS_BLACK(other->RChild))
				{
					//No.3 xB=BLACK xB->LChild=RED, xB->RChild=BLACK;
					SET_BLACK(other->LChild);
					SET_RED(other);
					R_Rotation(tree, other);
					other = parent->RChild;
				}
				//No.4 xB=BLACK xB=RChild=RED
				SET_COLOR(other, COLOR(parent));
				SET_BLACK(parent);
				SET_BLACK(other->RChild);
				L_Rotation(tree, parent);
				node = tree->root;
				break;
			}
		}
		else //node是其父节点的右孩子
		{
			other = parent->LChild;
			if (IS_RED(other))
			{
				//No.1 xB=RED
				SET_BLACK(other);
				SET_RED(parent);
				L_Rotation(tree, parent);
				other = parent->LChild;
			}
			if ((!other->LChild) || IS_BLACK(other->LChild) &&
				(!other->RChild) || IS_BLACK(other->RChild))
			{
				//No.2  xB=BLACK
				SET_RED(other);
				node = parent;
				parent = PARENTNODE(node);
			}
			else
			{
				if (!other->LChild || IS_BLACK(other->LChild))
				{
					//No.3 xB=BLACK xB->RChild=RED, xB->LChild=BLACK;
					SET_BLACK(other->RChild);
					SET_RED(other);
					L_Rotation(tree, other);
					other = parent->LChild;
				}
				//No.4 xB=BLACK xB=LChild=RED
				SET_COLOR(other, COLOR(parent));
				SET_BLACK(parent);
				SET_BLACK(other->LChild);
				R_Rotation(tree, parent);
				node = tree->root;
				break;
			}
		}
	}
	if (node)
	{
		SET_BLACK(node);
	}
}
//2.1 当做BST 去做删除
void deleteNode(LPRBTREE tree, LPNODE node)
{
	LPNODE child, parent;
	int color;					//删除节点兄弟的颜色
	//左右子树都存在
	if ((node->LChild) != NULL && (node->RChild) != NULL)
	{
		LPNODE replace = node;
		replace = replace->RChild;		//调整树:从右子树中拿最左边
		while (replace->LChild != NULL)
		{
			replace = replace->LChild;
		}
		//讨论删除节点是不是根节点
		if (PARENTNODE(node))
		{
			if (PARENTNODE(node)->LChild == node)
			{
				PARENTNODE(node)->LChild = replace;
			}
			else
			{
				PARENTNODE(node)->RChild = replace;
			}
		}
		else
		{
			tree->root = replace;
		}
		child = replace->RChild;
		parent = PARENTNODE(replace);
		color = COLOR(replace);
		if (parent == node)
		{
			parent = replace;
		}
		else
		{
			if (child)
			{
				SET_PARENT(child, parent);
			}
			parent->LChild = child;
			replace->RChild = node->RChild;
			SET_PARENT(node->RChild, replace);
		}
		//调整替换节点父节点
		replace->parentNode = node->parentNode;
		replace->color = node->color;
		replace->LChild = node->LChild;
		//调整删除节点父节点
		node->LChild->parentNode = replace;
		if (color == BLACK)
		{
			//调整树:
			deleteAdjustTree(tree, child, parent);
		}
		free(node);
		return;
	}
	if (node->LChild != NULL)
	{
		child = node->LChild;
	}
	else
	{
		child = node->RChild;
	}
	parent = node->parentNode;
	color = node->color;
	if (parent)
	{
		if (parent->LChild == node)
		{
			parent->LChild = child;
		}
		else
		{
			parent->RChild = child;
		}
	}
	else
	{
		tree->root = child;
	}
	if (color == BLACK)
	{
		//调整二叉树
		deleteAdjustTree(tree, child, parent);
	}
	free(node);
}
LPNODE search(LPNODE x, int key)
{
	if (x == NULL || x->key == key)
		return x;
	if (key < x->key)
	{
		return search(x->LChild, key);
	}
	else
	{
		return search(x->RChild, key);
	}
}
void deleteTreeNode(LPRBTREE tree, int key)
{
	LPNODE result = search(tree->root, key);
	if (result != NULL)
		deleteNode(tree, result);
}

int main()
{
	int array[] = { 10,40,30,60,90,70,20,50,80 };
	int arrayNum = 9;
	LPRBTREE tree = createRBTree();
	for (int i = 0; i < arrayNum; i++)
	{
		insertNode(tree, createNode(array[i]));
	}
	preOrder(tree->root);
	printf("\n");
	printf("删除:\n");
	deleteTreeNode(tree, 10);
	preOrder(tree->root);
	printf("\n");
	printf("删除:\n");
	deleteTreeNode(tree, 80);
	preOrder(tree->root);
	printf("\n");

	while (1);//防止闪屏
	return 0;
}

猜你喜欢

转载自blog.csdn.net/q244645787/article/details/128564757