算法导论 之 红黑树插入C语言文档格式.docx
- 文档编号:16375041
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:22
- 大小:709.93KB
算法导论 之 红黑树插入C语言文档格式.docx
《算法导论 之 红黑树插入C语言文档格式.docx》由会员分享,可在线阅读,更多相关《算法导论 之 红黑树插入C语言文档格式.docx(22页珍藏版)》请在冰豆网上搜索。
⑤、对任何一个结点,从该结点通过其子孙结点到达叶子结点(NIL)的所有路径上包含相同数目的黑结点。
以根结点为例,其通过子孙结点到达叶子节点(NIL)的路径有如下几种情况:
至此,大家应该能够明白性质⑤的真实含义了。
为了便于处理红黑树代码的边界条件,我们采用一个哨兵来代表NIL。
对于一个红黑树而言,哨兵NIL是一个与树内普通结点有相同域的对象。
它的color域为BLACK,而其他域(parent,lchild,rchild和key)的值我们并不关心。
总之,红黑树是通过以上5种性质的限制约束了该树的平衡性能——即:
该树上的最长路径长度不可能大于最短路径长度的2倍,从而确保对树操作的时间复杂度达到O(log2@N)。
3编码实现
3.1结构定义
①、常值定义:
增强代码可读性、方便代码修改
[cpp]viewplaincopyprint?
在CODE上查看代码片派生到我的代码片
/*常值定义*/
#defineRBT_COLOR_BLACK'
b'
/*颜色:
黑色*/
#defineRBT_COLOR_RED'
r'
红色*/
#defineRBT_LCHILD(0)/*类型:
左孩子*/
#defineRBT_RCHILD
(1)/*类型:
右孩子*/
#defineRBT_MAX_DEPTH(512)/*栈的深度(栈处理红黑树时使用)*/
代码1常值定义
②、节点结构:
在二叉查找树的结构基础上,新增color字段
/*结点结构*/
typedefstruct_rbt_node_t
{
intkey;
/*关键字*/
intcolor;
/*结点颜色:
RBT_COLOR_BLACK(黑)或RBT_COLOR_RED(红)*/
struct_rbt_node_t*parent;
/*父节点*/
struct_rbt_node_t*lchild;
/*左孩子节点*/
struct_rbt_node_t*rchild;
/*右孩子节点*/
}rbt_node_t;
代码2结点结构
③、树结构:
sentinel字段用于表示叶子结点(NIL)。
当树内结点的左(右)孩子为叶子结点时,则将左(右)孩子指针指向sentinel字段。
/*红黑树结构*/
typedefstruct
rbt_node_t*root;
/*根节点*/
rbt_node_t*sentinel;
/*哨兵节点*/
}rbt_tree_t;
代码3树结构
④、错误码:
用来记录错误返回的类型,以便快速的确定程序中存在的异常
/*错误码*/
typedefenum
RBT_SUCCESS/*成功*/
RBT_FAILED=~0x7fffffff/*失败*/
RBT_NODE_EXIST/*结点存在*/
}rbt_ret_e;
代码4错误码
⑤、宏定义:
可有效的增强代码的简洁性、复用性、易读性
#definerbt_set_color(node,c)((node)->
color=(c))
#definerbt_set_red(node)rbt_set_color(node,RBT_COLOR_RED)
#definerbt_set_black(node)rbt_set_color(node,RBT_COLOR_BLACK)
#definerbt_is_red(node)(RBT_COLOR_RED==(node)->
color)
#definerbt_is_black(node)(RBT_COLOR_BLACK==(node)->
/*设置左孩子*/
#definerbt_set_lchild(tree,node,left)\
{\
(node)->
lchild=(left);
\
if(tree->
sentinel!
=left){\
(left)->
parent=(node);
}\
}
/*设置右孩子*/
#definerbt_set_rchild(tree,node,right)\
rchild=(right);
=right){\
(right)->
/*设置孩子节点*/
#definerbt_set_child(tree,node,type,child)\
if(RBT_LCHILD==type){\
rbt_set_lchild(tree,node,child);
else{\
rbt_set_rchild(tree,node,child);
代码5宏定义
3.2创建对象
创建的初始红黑树对象是一棵空树,其根节点为NULL,但是此时必须为叶子结点(哨兵)分配好空间,并将叶子结点的颜色置为黑色(性质3),以方便后续对树的操作处理。
/******************************************************************************
**函数名称:
rbt_creat
**功能:
创建红黑树对象(对外接口)
**输入参数:
NONE
**输出参数:
**返回:
红黑树对象地址
**实现描述:
**注意事项:
**1、每个结点要么是红色的,要么是黑色的;
**2、根结点是黑色的;
**3、所有叶子结点(NIL)都是黑色的;
**4、如果一个结点是红色,则它的两个儿子都是黑色的;
**5、对任何一个结点,从该结点通过其子孙结点到达叶子结点(NIL)
**的所有路径上包含相同数目的黑结点。
**作者:
#Qifeng.zou#2013.12.24#
******************************************************************************/
rbt_tree_t*rbt_creat(void)
rbt_tree_t*tree=NULL;
tree=(rbt_tree_t*)calloc(1,sizeof(rbt_tree_t));
if(NULL==tree){
returnNULL;
}
tree->
sentinel=(rbt_node_t*)calloc(1,sizeof(rbt_node_t));
if(NULL==tree->
sentinel){
free(tree);
sentinel->
color=RBT_COLOR_BLACK;
root=tree->
sentinel;
returntree;
代码6创建对象
3.3旋转处理
在插入和删除过程中,可能破坏红黑树的5个性质之一,和平衡二叉树的处理相似,可通过旋转来恢复红黑树的性质,但红黑树的旋转只有右旋和左旋2种。
右旋处理:
以结点N为支点,进行右旋转的处理描述:
结点N的左孩子A取代N的位置,并将结点A的右孩子AR作为结点N的左孩子,再将结点N作为结点A的右孩子。
右旋处理对应的代码如下所示:
rbt_right_rotate
右旋处理
**tree:
红黑树
**node:
旋转支点
RBT_SUCCESS:
成功RBT_FAILED:
失败
**GG
**||
**N->
L
**/\/\
**LRLLN
**/\/\/\
**LLLRRLRRLRR
**/\
**RLRR
**说明:
节点N为旋转支点
#Qifeng.zou#2014.01.15#
voidrbt_right_rotate(rbt_tree_t*tree,rbt_node_t*node)
rbt_node_t*parent=node->
parent,*lchild=node->
lchild;
sentinel==parent){
root=lchild;
lchild->
parent=tree->
elseif(node==parent->
lchild){
rbt_set_lchild(tree,parent,lchild);
else{
rbt_set_rchild(tree,parent,lchild);
rbt_set_lchild(tree,node,lchild->
rchild);
rbt_set_rchild(tree,lchild,node);
代码7右旋处理
左旋处理:
结点N的左孩子B取代N的位置,并将结点B的左孩子BL作为结点N的右孩子,再将结点N作为结点B的左孩子。
左旋处理对应的代码如下:
rbt_left_rotate
左旋处理
R
**LRNRR
**LLLRRLRRLRL
**LLLR
voidrbt_left_e(rbt_tree_t*tree,rbt_node_t*node)
parent,*rchild=node->
rchild;
root=rchild;
rchild->
elseif(node==parent->
rbt_set_lchild(tree,parent,rchild);
rbt_set_rchild(tree,parent,rchild);
rbt_set_rchild(tree,node,rchild->
lchild);
rbt_set_lchild(tree,rchild,node);
代码8左旋处理
3.4插入操作
1)当向一棵空树中插入结点时,则新结点将作为整棵树根结点,且为黑色(性质2);
2)当向一棵非空树中插入一个结点时,新结点的颜色都是为红色。
插入成功后,需要判断是否破坏了红黑树的5个性质。
经过分析,可以发现,向非空树中插入一个结点,不可能破坏性质1、2、3、5,唯一可能被破坏只有性质4——出现2个连续的红结点[新节点和父节点为红色],且性质4被破坏,只有如下六种情况:
============================================================================
前提1:
父节点P为祖父节点G的左孩子
情况1):
叔结点U为红色
前提条件:
新结点N和父结点P都为红色,父结点P为G的左孩子
情况描述:
叔结点U为红色时[注:
此时不必关心新结点N是左孩子还是右孩子]
处理过程:
[代码:
参考rb_insert_fixup()中的case1]
①、将父结点P和叔结点U的颜色改为黑色,将祖父结点G改为红色
②、把祖父结点作为下一次判断的对象
情况2):
叔结点为黑色,新结点N为右孩子
叔结点U也为黑色,新结点N为右孩子时
参考rb_insert_fixup()中的case2]
①、调整颜色:
将父结点P改为黑色,将祖父结点改为红色
②、向右旋转90度:
父结点P取代祖父结点G的位置,同时将父结点的右子树PR作为祖父结点G的左子树,祖父结点G作为父结点P的右孩子
③、把祖父结点的父结点GP改为下一次判断的对象
情况3):
参考rb_insert_fixup()中的case3]
①、向左旋转90度:
新结点N取代父结点P的位置,同时将新结点的左子树NL作为父结点P的右子树,父结点P作为新结点N的左孩子
②、把父结点P改为下一次判断的对象[注意:
经过①、②、③处理后,情况3演变了情况2]
前提2:
父节点P为祖父节点G的右孩子
情况4):
新结点N和父结点P都为红色,父结点P为祖父G的右孩子
参考rb_insert_fixup()中的case4]
情况5):
叔结点U为黑色,新结点N为父结点P的左孩子
新结点N和父结点P都为红色,父结点P为祖父结点G的右孩子
叔结点U为黑色,新结点N为左孩子时
参考rb_insert_fixup()中的case5]
①、向右旋转90度:
新结点N取代父结点G的位置,同时将新结点的右子树NR作为父结点G的左子树,父结点G作为新结点的右孩子
②、把父结点P改为下一次判断的对象[此时case5演变为case6]
情况6):
叔结点U为黑色,新结点N为父结点P的右孩子
新结点N和父结点P都为红色,父结点P为G的右孩子
叔结点U为黑色,新结点N为右孩子时
参考rb_insert_fixup()中的case6]
①、颜色调整:
将祖父结点G改为红色,父结点P改为黑色
②、向左旋转90度:
父结点P取代祖父结点G的位置,同时将父结点的左子树PL作为祖父结点G的右子树,祖父结点G作为父结点P的左孩子
cpp]viewplaincopyprint?
rbt_creat_node
创建关键字为key的结点(内部接口)
**key:
**color:
结点颜色
**type:
新结点是父结点的左孩子还是右孩子
**parent:
父结点
RB_SUCCESS:
成功RB_FAILED:
新结点的左右孩子肯定是叶子结点
#Qifeng.zou#2013.12.23#
rbt_node_t*rbt_creat_node(rbt_tree_t*tree,intkey,intcolor,inttype,rbt_node_t*parent)
rbt_node_t*node=NULL;
node=(rbt_node_t*)calloc(1,sizeof(rbt_node_t));
if(NULL==node){
node->
color=color;
key=key;
lchild=tree->
rchild=tree->
if(NULL!
=parent){
rbt_set_child(tree,parent,type,node);
returnnode;
代码9创建key值结点
rbt_insert
向红黑树中增加节点(对外接口)
需被添加的关键字
失败RBT_NODE_EXIST:
节点存在
**1.当根节点为空时,直接添加
**2.将节点插入树中,检查并修复新节点造成红黑树性质的破坏
**红黑树的5点性质:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法导论 红黑树 插入C语言 算法 导论 插入 语言