C语言实现红黑树

本文介绍了如何使用C语言实现红黑树,讲解了红黑树的基本性质,并通过示例展示了1~9插入后的树形结构。文章还讨论了C89语言规范与现代编译器的差异,以及在不同环境下编写C程序需要注意的细节,强调了实践对于深入理解的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

<span style="font-family: 'Microsoft YaHei'; background-color: rgb(255, 255, 255);">红黑树是一种二叉搜索树,具有良好的性质,树高至多2lg(n+1)。</span>

 一棵红黑树是满足下列条件的二叉搜索树:

  1. 每个节点或是红色的或是黑色的。
  2. 根节点是黑色的。
  3. 叶子节点是黑色的。
  4. 如果一个节点是红色的,那么它的两个孩子是黑色的。
  5. 对每个节点,从该节点(不包括该节点)到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。

方案使用一个哨兵Nil来代表所有的NULL,根节点为T,根节点的父节点为Nil, 所有叶子节点为Nil。

红黑树的一个节点包含以下属性

typedef struct NODE
{
	struct NODE      *left;  // 左孩子
	struct NODE      *right; // 右孩子
	struct NODE      *p;     // 父节点
	TREE_TYPE        value;  // 值
	COLOUR           colour; // 颜色
} Tree, Node;


在写这个程序的过程中发现了很多问题,经受了一些BUG的折磨,希望我能回忆的起来:

1.假如定义一个函数

Node *Left(Node *x)
{
	return x->left;
}
那么这样调用可以吗?(C89)

Left( node )->left = Nil;
答案是不可以。

而如果文件保存为.cpp的是可以的,C++支持这种写法。

我们可以嵌套Left( Left(node) )不可以作为左值(不显然的嘛)。
2.不得不说 C89里所有变量必须在语句块最前面定义,不然会报一堆错误,之前一直用的轻量级的Dev C++ 开发环境编译器GCC4.8.1,写着更爽一些,不过调试器太简单,VS的调试器很强大可以看清楚数据的结构,这对于理解程序的结构更有好处,虽然它的古老语法不太人性。什么你说我用VS写的时候随便啊for(int i= 0; i<n; ++i)都可以,只能说你写的真的不是C(VS2013没用过不清楚)。对C程序恐怕不太好移植。

用KEIL4写嵌入式程序时。  比如int config_lcd() ; 这样的声明会有一个警告,这更严格了。应该写为

int config_lcd(void) 就没警告啦!那int main() {} 、 void main(){}都不行啦。int main(void)才是标准,

3.有时用这样写  

void counting_sort(char *source , char * des, int k )
{
    char c[k];
    .....  ....
}
GCC是可以通过的,然而有些激进。

      当然这些东西,很多书上会讲到,不过绝知此事要躬行,自己碰到这些问题才会理解更深刻。

下面是红黑树的代码

red_black_tree.h文件

#ifndef _RED_BLACK_TREE_H
#define _RED_BLACK_TREE_H

#define TREE_TYPE  int // 树的类型
#define RED        '0' // 红色
#define BLACK      '1' // 黑色
#define COLOUR      char
 

/* 红黑树节点 */
typedef struct NODE
{
	struct NODE      *left;  // 左孩子
	struct NODE      *right; // 右孩子
	struct NODE      *p;     // 父节点
	TREE_TYPE        value;  // 值
	COLOUR           colour; // 颜色
} Tree, Node;

Node *get_node(Node* parent, int key);


/**
*    x                       y
*   / \        ==>          / \
*  a   y    left rotate    x   r
*     / \                 / \
*    b   r               a   b
*/
void left_rotate( Node *x );

/**
* right_rotate   x                       y
			*   / \        <==          / \
			*  a   y    right rotate   x   r
			*     / \                 / \
			*    b   r               a   b
*/
void right_rotate( Node *y );

/**
* 返回 x 的父节点
*/
Node *P(Node *x);

/**
* 返回 x 的左孩子
*/
Node *Left(Node *x);

/**
* 返回 x 的右孩子
*/
Node *Right(Node *x);

/**
* 在 T 中搜索值 value 
* 返回指向该节点的指针
* 若不存在 返回 NULL
*/
Node *tree_seach(TREE_TYPE value);

/* 最小关键字元素 */
Node *tree_minimum(Node *x);

/**
* 修正插入节点 z 破坏的红黑树
*/
void rb_insert_fixup(Node *z);

/**
* 修正删除节点 z 破坏的红黑树
*/
void rb_delete_fixup(Node *x);

/**
* 向红黑树 T 插入值 value
*/
void rb_insert(TREE_TYPE value);

/**
* 向红黑树 T 删除值 value
*/
void rb_delete(TREE_TYPE value);

#endif

red_black_tree.c文件

/**
 ******************************************************************************
  * @file    red_black_tree.c 
  * @author  summer
  * @version V1.0
  * @date    2015-06-30
  * @brief   C语言实现红黑树  (C89)
  ******************************************************************************
  * @environment:
  * IDE:      Visual Studio 2010      
  * 
  ******************************************************************************
*/
#include"red_black_tree.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

Node *Nil = NULL;     // 公共空节点   Nil(T)
extern Tree *T;

/* 配置一个节点 */
Node *get_node(Node* parent, TREE_TYPE value)
{
    Node *tmp = (Node*)malloc(sizeof(Node));
	assert(tmp != NULL);
    tmp->value  = value;
    tmp->colour = RED;
    tmp->p = parent;
    tmp->left = tmp->right = Nil;
    return tmp;
}

/**
* 左孩子
*/
Node *Left(Node *x)
{
	return x->left;
}

/**
* 右孩子
*/
Node *Right(Node *x)
{
	return x->right;
}

/**
* 父节点
*/
Node *P(Node *x)
{
	return x->p;
}

/**
* left_rotate    x                       y
			*   / \        ==>          / \
			*  a   y    left rotate    x   r
			*     / \                 / \
			*    b   r               a   b
* 假设 根的父节点是 Nil   
*/
void left_rotate( Node *x)
{
	Node *y = x->right; // 看着图,很好理解
	if(y == Nil)
	{
		printf("Right(x) is NULL !\n");
		return;
	}

	x->right   = y->left;
	if(y->left != Nil)
	{
	    y->left->p = x;
	}
	y->p  = x->p;

	if( P(x) == Nil ) // root(T) 根节点
	{
	    T = y; 
	}
	else if (x == x->p->left )
	{
		x->p->left = y;
	}
	else
	{
		x->p->right = y;
	}

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

void right_rotate(Node *x)
{
	Node *y = x->left; // 看着图,很好理解
	if(y == Nil)
	{
		printf("Right(x) is NULL !\n");
		return;
	}

	x->left   = y->right;
	if(y->right != Nil)
	{
	    y->right->p = x;
	}
	y->p  = x->p;

	if( P(x) == Nil ) // root(T) 根节点
	{
	    T = y; 
	}
	else if (x == x->p->right )
	{
		x->p->right = y;
	}
	else
	{
		x->p->left = y;
	}

	y->right = x;
	x->p    = y;
}

/* 插入节点 O(lgn)*/
void rb_insert( TREE_TYPE value )
{
#if 1
	Node *y = Nil;
	Node *x = T;
	Node *z = Nil;

    if( T == NULL ) // 树是空的
	{
		T = get_node(Nil, value);
		T->colour = BLACK;
		return;
	}

	while(x != Nil)
	{
		y = x; // 保存 x
		if( value < x->value)
		{
			x = x->left;
		}
		else if(value > x->value)
		{
			x = x->right;
		}
		else return;
	}
	z = get_node(y, value);
	z->p = y;

	if(y == Nil)
	{
		T = z;//get_node(y, value);
		//return;
	}
	else if(value < y->value)
	{
		y->left  = z;//get_node(y, value);
	}
	else
	{
		y->right = z;//get_node(y, value);
	}

	rb_insert_fixup(z);//修正插入节点 z 破坏的红黑树
#endif
}

void rb_insert_fixup(Node *z)
{
	Node *y;
    while(z->p->colour == RED) // z是红色,如果P(z)为红色,则违反规则4
	{
		if( z->p == z->p->p->left )
		{
			y = z->p->p->right; // y 为 z 的叔节点
			if(y->colour == RED) // 如果z的叔节点为红色
			{
				z->p->colour = BLACK; // 把z的父节点涂黑
				y->colour    = BLACK; // 叔节点涂黑
				z->p->p->colour = RED;// 父节点的父节点涂黑
				z = z->p->p;         // z指向父节点的父节点, 不看图是不容易理清的
			}
			else 
			{
				if(z == z->p->right)
			    {
					z = z->p;
					left_rotate(z); // 执行一个左旋
			    }
			    z->p->colour    = BLACK;
			    z->p->p->colour = RED;
			    right_rotate(z->p->p);
			}
		}//if
		else // P(z) == Right( P( P(z) ) )
		{
			y = z->p->p->left;  // y 为 z 的叔节点
			if(y->colour == RED) // 如果z的叔节点为红色
			{
				z->p->colour = BLACK; // 把z的父节点涂黑
				y->colour    = BLACK; // 叔节点涂黑
				z->p->p->colour = RED;// 父节点的父节点涂黑
				z = z->p->p;         // z指向父节点的父节点
			}
			else 
			{
				if(z == z->p->left)
				{
					z = z->p;
					right_rotate(z);
				}
			    z->p->colour    = BLACK;
			    z->p->p->colour = RED;
			    left_rotate(z->p->p);
			}
		}//else
	}//while
	T->colour = BLACK;
}

/* v子树代替u子树, rb_delete 函数的辅助函数 */
void rb_transplant(Node *u, Node *v)
{
    if(u->p == Nil)
	{
		T = v;
	}
	else if(u == u->p->left)
	{
		u->p->left = v;
	}
	else
	{
		u->p->right = v;
	}
	v->p = u->p;
}
/* 查找元素  O(lgn) */
Node *tree_seach(TREE_TYPE value)
{
	Node *x = T;
	while( x != Nil && x->value != value )
	{
		x = (value < x->value) ? x->left : x->right;
	}
	return x;
}

/* 最小关键字元素 */
Node *tree_minimum(Node *x)
{
	while(x->left != Nil)
	{
		x = x->left;
	}
	return x;
}

void rb_delete_fixup( Node *x)
{
	Node *w = NULL;
	while(x != T && x->colour == BLACK )
	{
		if(x == x->p->left)     // x 是左子树
		{
			w =  x->p->right;   // x 的兄弟
			if(w->colour == RED) // x 的兄弟节点 w 是红色
			{
				w->colour = BLACK;
				x->p->colour = RED;
				left_rotate(x->p);
				w = x->p->right;
			}
			if( (w->left->colour == BLACK) && (w->right->colour == BLACK) )
			{// x 的兄弟节点 w 是黑色的, 且 w 的两个子节点都是黑色的
				w->colour = RED;
				x = x->p;
			}
			else
			{
				if( w->right->colour == BLACK)
				{// x 的兄弟节点 w 是黑色的,且 w 的左孩子是红色的,w 的右孩子是黑色的
					w->left->colour = BLACK;
					w->colour = RED;
					right_rotate(w);
					w = x->p->right;
				}
                // x 的兄弟节点 w 是黑色的, 且 w 的右孩子是红色的
			    w->colour = x->p->colour;
			    x->p->colour = BLACK;
			    w->right->colour = BLACK;
			    left_rotate(x->p);
		        x = T;
			}
		}//if
		else// x是右子树
		{
			w =  x->p->left;// x 的兄弟
			if(w->colour == RED) // x的兄弟节点是红色
			{
				w->colour = BLACK;
				x->p->colour = RED;
				right_rotate(x->p);
				w = x->p->left;
			}
			if( (w->right->colour == BLACK) && (w->left->colour == BLACK) )
			{
				w->colour = RED;
				x = x->p;
			}
			else 
			{
				if( w->left->colour == BLACK )
				{
					w->right->colour = BLACK;
					w->colour = RED;
					right_rotate(w);
					w = x->p->left;
				}
				w->colour = x->p->colour;
			    x->p->colour = BLACK;
			    w->left->colour = BLACK;
			    right_rotate(x->p);
			    x = T;
			}
		}//else
	}//while
	x->colour = BLACK;
}
/* 删除节点 O(lgn) */
void rb_delete(TREE_TYPE value)
{
	Node *x = NULL;// x 指向 y 的唯一子节点或指向 Nil
	Node *z = tree_seach( value); // O(lgn)
    Node *y = z;   // y 为从树中删除的节点或者移至树内的节点
	COLOUR y_original_colour; // 保存 y 的颜色
	if(z == Nil)
	{
		printf("Not found !\n");
		return;
	}
	y_original_colour = y->colour;
	if(z->left == Nil)
	{
		x = z->right;
		rb_transplant(z, z->right);
	}
	else if(z->right == Nil)
	{
		x = z->left;
		rb_transplant(z, z->left);
	}
	else// z 有两个节点
	{
		y = tree_minimum(z->right); // y指向z的后继
		y_original_colour = y->colour;
		x = y->right;
		if(y->p == z)
		{
			x->p = y;
		}
		else
		{
			rb_transplant(y, y->right);
			y->right = z->right;
			y->right->p = y;
		}
	    rb_transplant( z, y);
		y->left    = z->left;
		y->left->p = y;
		y->colour   = z->colour;
	}//else
	if(y_original_colour == BLACK)
	{
		rb_delete_fixup(x);
	}
	free(z);
	z = Nil;
	//printf("delete success\n");
}
 

测试代码main.c

#include"red_black_tree.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
extern Node *Nil;  // T.NULL
Node *T;           // T.root
int main(void)
{
	int i;
	Node *test_node;


    /* config Nil */
	Nil = (Node*)malloc( sizeof(Node) );
	assert(Nil != NULL);
	Nil->colour = BLACK; //nil的颜色设置为黑


	/* config T.root */
	T = NULL;


	for(i = 1; i < 10; ++i)
	{
		rb_insert(i);
		test_node = tree_seach(i);
		if(test_node != Nil)
		    printf("%d\n", test_node->value);
		else printf("Not found the value\n");
	}


	for(i = 1; i < 10; ++i)
	{
              rb_delete(i);
	}


	system("pause");
    return 0;
}
调试状态下我们可以看到红黑树的结构

1~9插入一棵红黑树

                     4b

                   /     \

               2r         6r

            /    \       /     \
         1b   3b    5b     8b

                               /     \

                             7r       9r

符合红黑树的性质。

其他函数亦实现了功能。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值