数据结构 - 红黑树学习

红黑树

红黑树算是用的比较多,但是平时自己很少写的一种数据结构了,先看下介绍:

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。

看~ 典型是用来实现关联数组,能想到什么数据结构呢?list map set这些容器的底层都是红黑树来实现的。

红黑树和AVL树(平衡二叉查找树)

红黑树并不是完全平衡的一棵树,所以红黑树是在平均时间(经验)上为O(log n)的复杂度,包括插入,删除和查找。

红黑树规则

  1. 所有节点都分为红色和黑色两种颜色节点。
  2. 所有的叶子节点(外节点)都是黑色。
  3. 根节点是黑色。
  4. 所有的节点到它的叶子节点的路径的黑深度是相等的。
  5. 红色节点的两个孩子节点一定是黑色的。

这5条看起来很多,但其实很容易理解,这里最重要的是任意一个节点到它的叶子节点的路径的黑深度是相等的。它保证了树的平衡。而红色节点的孩子节点是黑色的则保证了树的黑色和红色节点的均衡。

红黑树查找

红黑树的查找很简单,左小右大的结构,相当于二分查找,和AVL树的查找是类似的,时间复杂度上面也说了平均为: log(n).

红黑树的插入和删除

这是红黑树最难的两个地方, 插入节点一定插入的位置是叶子,当插入的时候需要判断是否红黑树还满足上面5条性质,假如不满足要进行旋转操作。

为了保持黑深度的相等,插入的节点一定是红色节点

但是! 插入一个红色节点之后,可能会破坏红黑树的性质5. 所以插入之后判断是否满足。不满足的话旋转。

旋转有四种情况,虽然都是单旋转,但是每次旋转的步骤并不相同,因为画起来很麻烦,我直接找了书上的图片~


  • 情况1

这个是除了插入直接符合外最简单的情况,就是插入节点的父节点是红色,祖父节点是黑色,则只用把父节点变到祖父节点的位置,并变为黑色,祖父节点变为父节点的右孩子。就可以了。


  • 情况2

这种情况和第一种唯一不同的点在于孩子节点插入到了父亲节点的右节点,所以要先进行一次左旋转,一次右旋转。

(类似AVL树的双旋转)


  • 情况3

这个和情况1一样,就是S不为NULL了,但这个是有限制的,可以看到P移动到G的位置了,P为红色,也就是说原RB树的G的父节点要是黑色,不然就是情况4了。


  • 情况4

这个情况就是情况3的升级版本,就是说G的父节点还是红色,那么就要循环向上继续做,继续旋转,可能会遇到1 2 3的情况,就可以成功解决。


代码

我自己尝试写了一下红黑树的实现,Insert没有完全完成。以后慢慢更新这篇博客吧。

还是相对比较麻烦的。

//
//  main.cpp
//  Red_Black_Tree
//
//  Created by Alps on 15/5/13.
//  Copyright (c) 2015年 chen. All rights reserved.
//

#include <iostream>
#include <string>
using namespace std;
typedef bool rb_tree_color;
const rb_tree_color rb_tree_red = false; //红色为false
const rb_tree_color rb_tree_black = true; //黑色为true

struct rb_tree_node_base{
    typedef rb_tree_color color_type;
    typedef rb_tree_node_base* base_ptr;

    color_type color;
    base_ptr parent;
    base_ptr left;
    base_ptr right;

    static base_ptr minnum(base_ptr T){
        while(T->left != NULL){
            T = T->left;
        }
        return T;
    }

    static base_ptr maxnum(base_ptr T){
        while(T->right != NULL){
            T = T->right;
        }
        return T;
    }
};

struct rb_tree_node : public rb_tree_node_base{
    typedef rb_tree_node* link_type;
    int value_field;
};

class rb_tree{
public:
    typedef rb_tree_node* link_type;
    typedef size_t size_type;
    typedef rb_tree_node_base* base_ptr;
    link_type header;
    size_type node_count;

    link_type& root() const{
        return (link_type&) header->parent;
    }
    link_type& leftmost() const{
        return (link_type&) header->left;
    }
    link_type& rightmost() const{
        return (link_type&) header->right;
    }

    //取极大值和极小值 用rb_tree_node自带的来实现
    static link_type minnum(link_type T){
        return (link_type)rb_tree_node::minnum(T);
    }
    static link_type maxnum(link_type T){
        return (link_type)rb_tree_node::maxnum(T);
    }

protected:
    link_type get_node(){
        return (link_type)malloc(sizeof(struct rb_tree_node));
    }

    static link_type& left(base_ptr x){
        return (link_type&)(x->left);
    }
    static link_type& right(base_ptr x){
        return (link_type&)(x->right);
    }
    static link_type& parent(base_ptr x){
        return (link_type&)(x->parent);
    }

private:
    void init(){
        header = get_node();
        header->color = rb_tree_red;
        root() = NULL;
        leftmost() = header;
        rightmost() = header;
    }

public:
    rb_tree():node_count(0){
        init();
    }
    ~rb_tree(){
//        clear();
//        put_node(header);
    }
private:
    link_type& insert_tree(base_ptr x, base_ptr y, const int v);

public:
    link_type insert_equal(const int v){
        link_type y = header;
        link_type x = root();
        while (x != 0) {
            y = x;
            x = (v > x->value_field ? left(x) : right(x));
        }
        return insert_tree(x, y, v);
    }
    pair<link_type, bool> insert_unique(const int v){
        link_type y = header;
        link_type x = root();
        while (x != 0) {
            y = x;
            x = v > x->value_field ? right(x) : left(x);
        }
        link_type z = y;
        if (v < y->value_field) {
            if (y->left == NULL) {
                return make_pair(_insert(x, y, v), true);
            }else{
                z = (link_type)z->parent; //不太懂
            }

        }

        return make_pair(y, false);
    }

    link_type _insert(base_ptr x, base_ptr y, const int v){
        return (link_type)x;
    }
};

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    return 0;
}

写这个代码的时候,我参考了源码,insert部分还没有写完,主要是不是模板,在使用迭代器的时候有点麻烦。

红黑树最重要的是知道运行院里,知道底层的一些操作,和性能。

时间: 2024-10-11 06:54:46

数据结构 - 红黑树学习的相关文章

数据结构 - 红黑树(Red Black Tree)插入详解与实现(Java)

最终还是决定把红黑树的篇章一分为二,插入操作一篇,删除操作一篇,因为合在一起写篇幅实在太长了,写起来都觉得累,何况是阅读并理解的读者. 红黑树删除操作请参考 数据结构 - 红黑树(Red Black Tree)删除详解与实现(Java) 现在网络上最不缺的就是对某个知识点的讲解博文,各种花样标题百出,更有类似"一文讲懂xxx","史上最简单的xxx讲解","xxx看了还不懂你打我"之类云云.其中也不乏有些理论甚至是举例都雷同的两篇不同文章,至于作

数据结构-红黑树

转自:http://dongxicheng.org/structure/red-black-tree/ 1. 简介 红黑树是一种自平衡二叉查找树.它的统计性能要好于平衡二叉树(AVL树),因此,红黑树在很多地方都有应用.在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持).它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它

红黑树学习

红黑树是工程中用的比较多的一个数据结构,它的优点是查找的复杂度是O(lgN), 而且红黑树会在插入 数据的时候保持平衡,抑制复杂度的暴涨.虽然它没有hashtable那样高效,但是不用事先规划并分配空间.那么它是怎么做到的呢? 下面是它的特性: 1.红黑树由红色和黑色的元素构成(着色) 2.红色节点没有红色的子节点(红色与红色是宿敌) 3.所有从根节点到叶子节点的黑色节点数量相等(左右平衡). 可以推出: 1根节点是黑色的. 2.红色节点的两个子节点都是黑色的 插入操作 数据是怎么插入呢?这里忘

算法导论 红黑树 学习 旋转(二)

学习算法 还是建议看看算法导论 算法导论第三版 如果不看数学推导 仅看伪代码 难度还是适中 本系列只是记录我的学习心得 和伪代码转化代码的过程 深入学习 还是建议大家看看算法书籍 教程更加系统. 本文参考算法导论第13章节 红黑树 代码由本人写成 转载请标明出处 红黑树是一个带颜色的二叉树 有以下5点性能 1 每个节点或者红色或者黑色 2 根节点黑色 3 每个叶子节点(nil)为黑色 4 如果一个节点是红色的则它的两个子节点都是黑色 5 每个节点 该节点到子孙节点的路径上 黑色节点数目相同 如图

算法导论 红黑树 学习 删除(四)

版权声明:本文为博主原创文章,未经博主允许不得转载.技术博客 http://blog.csdn.net/stecdeng 技术交流群 群号码:324164944 欢迎c c++ windows驱动爱好者 服务器程序员沟通交流 学习算法 还是建议看看算法导论 算法导论第三版 如果不看数学推导 仅看伪代码 难度还是适中 本系列只是记录我的学习心得 和伪代码转化代码的过程 深入学习 还是建议大家看看算法书籍 教程更加系统. 本文参考算法导论第13章节 红黑树 代码由本人写成 转载请标明出处 先看看不做

数据结构-红黑树详解

介绍: 红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组. 它是在1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees).后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的"红黑树". 红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能. 它虽然

数据结构——红黑树

红黑树是二叉排序树的改进, 红黑树有几个特点: 1:节点只有2中颜色,红色和黑色. 2:根节点一定是黑色节点. 3:红色节点的子节点一定是黑色节点. 4:黑色高度(根节点到每个叶子节点的路径长度包含相同的黑色节点)相等. 规定的插入的节点一定是红色节点, 红黑树的插入节点后需要调整的规则,插入节点需要调整的情况有3种: 情况1:插入的节点的父节点和叔叔节点都为红色: 以上情况节点4为插入节点(当前节点),这种情况调整方式是将父节点和叔叔节点都调整为黑色节点,祖父节点调整为红色,将祖父节点变为当前

红黑树学习资料总结

关于红黑树的插入:红黑树并没有我们想象的那么难(上) 关于红黑树的删除:红黑树插入删除 关于红黑树的源码剖析:红黑树C源码实现与剖析

红黑树 学习笔记

  性质: 节点非黑即红 根和叶子节点是黑(这里说的叶子节点指填充后的树的叶子节点,NIL节点) 红节点的父节点是黑节点 任意一个节点到以他为根的叶子节点所经过的黑节点数目(不包括自身,但包括叶子节点)的个数是一样. 红黑树可以在O(lgn)时间内完成查询搜索操作,另插入操作需要最多2次旋转,删除操作需要最多3次旋转.