赞
踩
#define RED 0; #define BALCK 1; typedef int KEY_TYPE; int KEY_COMPARE(KEY_TYPE a,KEY_TYPE b) { //红黑树结点比较,后续可自行实现,目前代码里的还是使用的>比较 } typedef struct _rbtree_node { unsigned char color; struct _rbtree_node *left; struct _rbtree_node *right; struct _rbtree_node *parent; KEY_TYPE key; void *value; } rbtree_node; typedf struct _rbtree{ rbtree_node * root; rbtree_node * nil; }rbtree; //左旋 void _left_roate(rbtree *T,rbtree_node *x) { 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->parent->left == x) { x->parent->left = y; }else if (x->parent->right == x) { x->parent->right = y; } x->parent = y; y->left= x; } //右旋 void _right_rotate(rbtree *T,rbtree_node *y) { rbtree_node *x=y->left; y->left = x->right; if(x->right != T->nil) { x->right->parent = y; } x->parent = y ->parent; if(y->parent == T->nil) { T->root = x ; }else if(y == y->parent->left) { y->parent->left = x; }else { y->parent->right = x; } y->parent = x; x->right= y; } //插入结点 void rbtree_insert(rbtree *T,rbtree_node *z) { rbtree_node *x = T->root; rbtree_node *y; while(x ! =T->nil) { //需要在遍历时保存对应挂载的结点 y=x; if(z->key < x->key){ x=x->left; }else if(z->key > x->key){ x=x->right; }else { //相同时可以自行处理,例如,对z->key数据+0.01 或者 直接返回 return; } } z->parent = y; if(y == T->nil) { T->root = z; }else if(z->key < y->key){ y->left = z; }else { y->right =z; } z->left = T->nil; z->right = T-> nil; z->color = RED; } /*所有插入的情况 1.插入节点的父节点是黑色的情况有4种 这种情况不需要进行额外处理。 2.插入节点的父节点是红色的情况有8种 这种情况不满足红黑树的性质4,需要进行额外的修复处理。 这8种情况中: 1) 叔父节点不是红色的情况有4种 这些情况都是非上溢,需要通过重新染色和旋转来进行修复 2) 叔父节点是红色的情况有4种 这些情况都是上溢的,只需要通过祖父节点上溢合并和染色即可完成修复 */ void fix_rbtree(rbtree* T, rbtree_node* z) { //循环处理的时候,确保只对红色结点进行处理 //只有在父节点为红色的时候,破坏了红黑树的性质才需要调整 while (z->parent != T->nil && z->parent->color == RED) { //不满足红黑树的性质,需要进行调整 //叔父结点不是红色,则表示非上溢 //首选要确定自己的父节点是左子树还是右子树 if (z->parent == z->parent->parent->left) { //叔父结点在右边 rbtree_node* y = z->parent->parent->right; //父结点在左边 if (y->color != RED) { //这种情况下需要重新染色和旋转 //判断当前节点是左子树还是右子树,若和父节点在一条线上只要旋转一次,再进行染色 if (z == z->parent->right) { _left_rotate(T, z->parent); } z->parent->color = BLACK; z->parent->parent->color = RED; _right_rotate(T, z->parent->parent); //永远只对红色节点进行操作 z = z->parent->parent; } else { //叔父节点为红色,则表示为上溢插入(2-3-4树最多三个节点):黑 - 黑红 if (z->parent !=T->nil) z = z->parent->parent; z->color = RED; z->left->color = BLACK; z->right->color = BLACK; } } else { //插入的情况如上,省略 } } T->root->color = BLACK; } /*红黑树删除的操作 1.删除红色 - 对红黑树无影响 2.删除黑色 2.1 有两个红色叶子节点:不可能被直接删除,因为会找它的子节点替代删除,因此不用考虑这种情况 2.2 只一红色叶子节点:用删除节点的唯一子节点对其进行替代将替代节点染成黑色 2.3 没有红色叶子节点 2.3.1兄弟节点为黑色:这种情况若直接删除,会破会红黑树的平衡 2.3.1.1兄弟节点至少有一个红色的叶子节点,将这个红色叶子节点借过来 -》先删除该黑色节点,若兄弟节点和红色叶子节点是LR排布,则先左旋后,再根据新的兄弟节点进行右旋,最后将旋转后的左右节点改成黑色,保持平衡 2.3.1.2兄弟节点没有红色的叶子节点-需要父节点向下合并进行修复 1.父节点为红色:只需改色,父节点向下合并改为黑色,子节点改为红色 2.父节点为黑色:直接将父节点当成被删除的节点处理,来修复父节点的下溢情况递归处理 2.3.2兄弟节点为红色:通过旋转将需要删除节点的兄弟节点为黑色,再根据2.3.1修复红黑树
红黑树的平衡
1.红黑树的五条性质,是为了保证红黑树为4阶B树
2.红黑树的最大高度是2*log2(n+1),依然是 O(logn) 级别,因为高度不会很大进而维持一种相对平衡的状态。相较于AVL树,红黑树的平衡标准相对宽松:没有一条路径会大于其他路径的2倍,这是一种弱平衡,黑高度平衡。
3.搜索的平均时间复杂度:O(logn);添加的平均时间复杂度:O(logn),O(1) 次的旋转操作;删除的平均时间复杂度:O(logn),O(1) 次的旋转操作
红黑树和AVL树对比
1.搜索的次数远远大于插入和删除,选择AVL树;搜索、插入、删除次数几乎差不多,选择红黑树
2.相对于AVL树来说,红黑树牺牲了部分平衡性以换取插入/删除操作时少量的旋转操作,整体来说性能要优于AVL树
3.红黑树的平均统计性能优于AVL树,实际应用中更多选择使用红黑树
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。