• 关联式容器


    AVL tree

      为了确保整棵树的深度为O(logN),加了额外的平衡条件“任何结点的左右子树高度相差最多1”。

      调整规则:如果某一个子树平衡被打破,那么根据新插入的节点的位置可以分为以下几种:(X是被打破平衡的那个子树的根节点)

    1. 插入点位于X的左子节点的左子树——左左
    2. 插入点位于X的左子节点的右子树——左右
    3. 插入点位于X的右子节点的左子树——右左
    4. 插入点位于X的右子节点的右子树——右右

      1.4为外插可用于单旋;2,3为内插可用于双旋。

    RB-tree 

      另一种被广泛使用的平衡二叉搜索树,也是SGI STL唯一实现的搜寻树,作为关联式容器的底层机制之用。RB-tree的平衡条件虽然不同于AVL-tree(都是二叉搜索树),但同样运用了单旋转和双旋转修正操作。RB-tree的规则:

    1. 每个节点不是红色就是黑色;
    2. 根节点为黑色;
    3. 如果节点为红,其子节点必须为黑;
    4. 任一节点到NULL(树尾端)的任何路径,所含黑节点数必须相同。

      根据规则四:新增节点必须为红色;根据规则三:新增节点的父节点为黑色。

      假设新增节点为X,父节点为P,祖父结点为G,伯父结点为S,曾祖父结点为GG;所以新增结点必为叶节点且为红(规则4),若P为红(违反规则3要调整),G必为黑,以下四种考虑

      1.S为黑且X为外侧插入,先对PG做一次单旋,在更改PG颜色,即可满足规则3;

      2.S为黑且X为内插,先对PX做一次单旋,更改GX颜色,再对G做单旋,即可满足规则3;

      3.S为红且X为外侧插入,先对PG做单旋,并改X颜色,如果此时GG为黑,则结束。

      4.S为红且X为外侧插入,先对PG做单旋,并改X颜色,如果此时GG为,继续向上调整直到不再有父子连续为红情况。

    RB-tree的结点设计

    //RB-tree特有的颜色定义
    typedef bool __rb_tree_color_type;
    const __rb_tree_color_type __rb_tree_red = false;  //红色被定义为0
    const __rb_tree_color_type __rb_tree_black = true;  //黑色被定义为1 
    //RB-tree节点基本结构
    struct __rb_tree_node_base {
        typedef __rb_tree_color_type  color_type;
        typedef __rb_tree_node_base* base_ptr;
    
        color_type color;        // 节点颜色,非黑即红
        base_ptr parent;        // 指向父节点,由于RB-tree时常要上溯其父节点
        base_ptr left;         // 指向左子节点
        base_ptr right;        // 指向右子节点
    
        // 一直往左走,就能找到红黑树的最小值节点
        // 二叉搜索树的性质
        static base_ptr minimum(base_ptr x)
        {
            while (x->left != 0) x = x->left;
            return x;
        }
        // 一直往右走,就能找到红黑树的最大值节点
        // 二叉搜索树的性质
        static base_ptr maximum(base_ptr x)
        {
            while (x->right != 0) x = x->right;
            return x;
        }
    };
    
    // 真正的节点定义,采用双层节点结构
    // 基类中不包含模板参数
    template <class Value>
    struct __rb_tree_node : public __rb_tree_node_base
    {
        typedef __rb_tree_node<Value>* link_type;
        Value value_field;    // 即节点值
    };

    RB-tree的迭代器

    struct __rb_tree_base_iterator
    {
        typedef __rb_tree_node_base::base_ptr base_ptr;
        typedef bidirectional_iterator_tag iterator_category;
        typedef ptrdiff_t difference_type;
    
        base_ptr node;    // 用来连接红黑树的节点
    
        // 寻找该节点的后继节点上
        void increment()
        {
            if (node->right != 0) { // 如果存在右子节点
                node = node->right;       //【情况1】直接跳到右子节点上
                while (node->left != 0) // 然后一直往左子树走,直到左子树为空
                    node = node->left;
            }
            else {                    // 没有右子节点【情况2】
                base_ptr y = node->parent;    // 找出父节点
                while (node == y->right) {    // 如果该节点一直为它的父节点的右子节点
                    node = y;                       // 就一直往上找,直到不为右子节点为止
                    y = y->parent;
                }
                if (node->right != y)      // 若此时该节点不为它的父节点的右子节点
                    node = y;               // 此时的父节点即为要找的后继节点【情况3】
                    // 否则此时的node即为要找的后继节点【情况4】
                    // 我们要寻找根节点的下一个节点,而根节点没有右子节点
                    // 此种情况需要配合rbtree的header节点的特殊设计,后面会讲到
            }
        }
    
        // 寻找该节点你的前置节点
        void decrement()
        {
            if (node->color == __rb_tree_red && // 如果此节点是红节点
                node->parent->parent == node)       // 且父节点的父节点等于自己
                node = node->right;                               // 则其右子节点即为其前置节点
                // 以上情况发生在node为header时,即node为end()时
                // 注意:header的右子节点为mostright,指向整棵树的max节点,后面会有解释
            else if (node->left != 0) {                 // 如果存在左子节点
                base_ptr y = node->left;            // 跳到左子节点上
                while (y->right != 0)               // 然后一直往右找,知道右子树为空
                    y = y->right;
                node = y;                          // 则找到前置节点
            }
            else {                                   // 如果该节点不存在左子节点
                base_ptr y = node->parent;         // 跳到它的父节点上
                while (node == y->left) {          // 如果它等于它的父子节点的左子节点
                    node = y;                   // 则一直往上查
                    y = y->parent;
                }                               // 直到它不为父节点的左子节点未知
                node = y;                       // 此时他的父节点即为要找的前驱节点
            }
        }
    };
    
    template <class Value, class Ref, class Ptr>
    struct __rb_tree_iterator : public __rb_tree_base_iterator
    {
        //...型别声明
        // 迭代器的构造函数
        __rb_tree_iterator() {}
        __rb_tree_iterator(link_type x) { node = x; }
        __rb_tree_iterator(const iterator& it) { node = it.node; }
        // 提领和成员访问函数,重载了*和->操作符
        reference operator*() const { return link_type(node)->value_field; }
        pointer operator->() const { return &(operator*()); }
        // 前置++和后置++
        self& operator++() { increment(); return *this; }
        self operator++(int) {
            self tmp = *this;
            increment();        // 直接调用increment函数
            return tmp;
        }
        // 前置--和后置--
        self& operator--() { decrement(); return *this; }
        self operator--(int) {
            self tmp = *this;
            decrement();        // 直接调用decrement函数
            return tmp;
        }
    };

    RB-tree的数据结构

    template <class Key, class Value, class KeyOfValue, class Compare,
              class Alloc = alloc>
    class rb_tree {
    protected:
      typedef void* void_pointer;
      typedef __rb_tree_node_base* base_ptr;
      typedef __rb_tree_node<Value> rb_tree_node;
      typedef simple_alloc<rb_tree_node, Alloc> rb_tree_node_allocator; // 专属配置器
      typedef __rb_tree_color_type color_type;
    public:
        // 一些类型声明
      typedef Key key_type;
      typedef Value value_type;
      typedef value_type* pointer;
      typedef const value_type* const_pointer;
      typedef value_type& reference;
      typedef const value_type& const_reference;
      typedef rb_tree_node* link_type;
      typedef size_t size_type;
      typedef ptrdiff_t difference_type;
    protected:
        link_type get_node(){return rb_tree_node_allocator::allocate();}
        void put_node(link_type p){rb_tree_node_allocator::deallocate(p);}
        link_type create_node()
        {
            link_type tmp=get_node();//配置空间
            __STL_TRY
            {
                construct(&tmp->value_field,x);
            }
            __STL_UNWIND(put_node(tmp));
            return tmp;
        }
        link_type clone_node(link_type x)
        {
            link_type tmp=create_node(x->value_field);
            tmp->color=x->color;
            tmp->left=0;
            tmp->right=0;
            return tmp;
        }
        void destroy_node(link_type p)
        {
            destroy(&p->value_field);
            put_node(p);
        }
    protected:
      // RB-tree的数据结构
      size_type node_count; // 记录树的节点个数
      link_type header;         // header节点设计
      Compare key_compare;  // 节点间的键值大小比较准则
    
      // 以下三个函数用来取得header的成员
      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; }
    
      // 以下六个函数用来取得节点的成员
      static link_type& left(link_type x) { return (link_type&)(x->left); }
      static link_type& right(link_type x) { return (link_type&)(x->right); }
      static link_type& parent(link_type x) { return (link_type&)(x->parent); }
      static reference value(link_type x) { return x->value_field; }
      static const Key& key(link_type x) { return KeyOfValue()(value(x)); }
      static color_type& color(link_type x) { return (color_type&)(x->color); }
    
      // 以下六个函数用来取得节点的成员,由于双层设计,导致这里需要两个定义
      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); }
      static reference value(base_ptr x) { return ((link_type)x)->value_field; }
      static const Key& key(base_ptr x) { return KeyOfValue()(value(link_type(x)));}
      static color_type& color(base_ptr x) { return (color_type&)(link_type(x)->color); }
    
      // 求取极大值和极小值,这里直接调用节点结构的函数极可
      static link_type minimum(link_type x) {
        return (link_type)  __rb_tree_node_base::minimum(x);
      }
      static link_type maximum(link_type x) {
        return (link_type) __rb_tree_node_base::maximum(x);
      }
    
    public:
        // RBTree的迭代器定义
        typedef __rb_tree_iterator<value_type, reference, pointer> iterator;
    private:
        //...
        void init() {   //构造一个空tree
            header = get_node();   //产生一个节点空间,令header指向它
            color(header) = __rb_tree_red;  //令header为红色,用来将
                                            //root与header区分开
            root() = 0;
            leftmost() = header;       //header的左子节点为自己
            rightmost() = header;      //header的右子节点为自己
        }
    public:
        rb_tree(const Compare& comp=Compare()):node_count(0),key_compare(comp){init();}
        ~rb_tree()
        {
            clear();
            put_node(hander);
        }
        rb_tree<Key,Value,KeyOfValue,Compare,Alloc>&
        operator=(const rb_tree<Key,Value,KeyOfValue,Compare,Alloc>& x);
    public:
        Compare key_comp() const { return key_compare; }  // 由于红黑树自带排序功能,所以必须传入一个比较器函数
        iterator begin() { return leftmost(); }        // RBTree的起始节点为左边最小值节点
        const_iterator begin() const { return leftmost(); }
        iterator end() { return header; }                         // RBTree的终止节点为右边最大值节点
        const_iterator end() const { return header; }
        bool empty() const { return node_count == 0; }    // 判断红黑树是否为空
        size_type size() const { return node_count; }     // 获取红黑树的节点个数
        size_type max_size() const { return size_type(-1); }  // 获取红黑树的最大节点个数,s// 没有容量的概念,故为sizetype最大值
    public:
        pair<iterator,bool> insert_unique(const value_type& x);//保持结点值独一无二
        iterator insert_equal(const value_type& x);//允许结点值重复
    };

    RB-tree的构造与内存管理

      RB-tree构造方式有两种,一种是以一个现有的RB-tree复制一个新的RB-tree,另一种是产生一棵空树。

    rb_tree<int, int, identity<int>, less<int> > itree;
    rb_tree(const Compare& comp = Compare())
        : node_count(0), key_compare(comp)  {  init();  }
    void init() {   //构造一个空tree
        header = get_node();   //产生一个节点空间,令header指向它
        color(header) = __rb_tree_red;  //令header为红色,用来将
                                    //root与header区分开
        root() = 0;
        leftmost() = header;       //header的左子节点为自己
        rightmost() = header;      //header的右子节点为自己
    }

      为了控制边界结点,在走到根节点时要特殊处理,为父节点在设计一个根节点hander,在插入结点时不仅要根据RB-tree的特性来维护树,而且还需要hander的正确性,使其父节点指向根节点,左子结点指向最小结点,右子结点指向最大结点。初始状态如下图

    RB-tree的元素操作

      RB-tree在修正平衡时有三种操作:更改颜色结点,左旋,右旋。在插入时也提供两种操作:insert_unique(插入的键值唯一)、insert_equal(允许插入重复键值)

    // 此插入函数不允许重复
    // 返回的是一个pair,第一个元素为红黑树的迭代器,指向新增节点
    // 第二个元素表示插入操作是否成功的
    template<class Key , class Value , class KeyOfValue , class Compare , class Alloc>  
    pair<typename rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::iterator , bool>  
    rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::insert_unique(const Value &v)  
    {  
        rb_tree_node* y = header;    // 根节点root的父节点  
        rb_tree_node* x = root();    // 从根节点开始  
        bool comp = true;  
        while(x != 0)  
        {  
            y = x;  
            comp = key_compare(KeyOfValue()(v) , key(x));    // v键值小于目前节点之键值?  
            x = comp ? left(x) : right(x);   // 遇“大”则往左,遇“小于或等于”则往右  
        }  
        // 离开while循环之后,y所指即插入点之父节点(此时的它必为叶节点)  
        iterator j = iterator(y);     // 令迭代器j指向插入点之父节点y  
        if(comp)     // 如果离开while循环时comp为真(表示遇“大”,将插入于左侧)  
        {  
            if(j == begin())    // 如果插入点之父节点为最左节点  
                return pair<iterator , bool>(_insert(x , y , z) , true);// 调用_insert函数
            else     // 否则(插入点之父节点不为最左节点)  
                --j;   // 调整j,回头准备测试  
        }  
        if(key_compare(key(j.node) , KeyOfValue()(v) ))  
            // 新键值不与既有节点之键值重复,于是以下执行安插操作  
            return pair<iterator , bool>(_insert(x , y , z) , true);  
        // 以上,x为新值插入点,y为插入点之父节点,v为新值  
    
        // 进行至此,表示新值一定与树中键值重复,那么就不应该插入新值  
        return pair<iterator , bool>(j , false);  
    }
    
    //插入新值:节点键值允许重复
    //返回值是一个RB-tree迭代器,指向新增节点
    template<class Key , class Value , class KeyOfValue , class Compare , class Alloc>  
    pair<typename rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::iterator , bool>  
    rb_tree<Key , Value , KeyOfValue , Compare , Alloc>::insert_equal(const Value &v)  
    {
        link_type y = header;
        link_type x = root();   //从根节点开始
        while (x != 0) {             //从根节点开始,往下寻找合适的插入点
            y  = x;
            x = key_compare(KeyOfValue()(v), key(x)) ? left(x)  : right(x);
            //以上,遇“大”则往左,遇“小于或等于”则往右
        }
        return _insert(x, y, v);// 以上,x为新值插入点,y为插入点之父节点,v为新值  
    }

       无论是哪一种插入方式,最终都需要调用__insert()函数

    // 真正地插入执行程序 _insert()  
    // 返回新插入节点的迭代器
    template<class Key , class Value , class KeyOfValue , class Compare , class Alloc>  
    typename<Key , Value , KeyOfValue , Compare , Alloc>::_insert(base_ptr x_ , base_ptr y_ , const Value &v)  
    {  
        // 参数x_ 为新值插入点,参数y_为插入点之父节点,参数v为新值  
        link_type x = (link_type) x_;  
        link_type y = (link_type) y_;  
        link_type z;  
        // key_compare 是键值大小比较准则。应该会是个function object  
        if(y == header || x != 0 || key_compare(KeyOfValue()(v) , key(y) ))  
        {  
            z = create_node(v);    // 产生一个新节点  
            left(y) = z;           // 这使得当y即为header时,leftmost() = z  
            if(y == header)  
            {  
                root() = z;  
                rightmost() = z;  
            }  
            else if(y == leftmost())     // 如果y为最左节点  
                leftmost() = z;          // 维护leftmost(),使它永远指向最左节点  
        }  
        else  
        {  
            z = create_node(v);        // 产生一个新节点  
            right(y) = z;              // 令新节点成为插入点之父节点y的右子节点  
            if(y == rightmost())  
                rightmost() = z;       // 维护rightmost(),使它永远指向最右节点  
        }  
        parent(z) = y;      // 设定新节点的父节点  
        left(z) = 0;        // 设定新节点的左子节点  
        right(z) = 0;       // 设定新节点的右子节点  
        // 新节点的颜色将在_rb_tree_rebalance()设定(并调整)  
        _rb_tree_rebalance(z , header->parent);      // 参数一为新增节点,参数二为根节点root  
        ++node_count;       // 节点数累加  
        return iterator(z);  // 返回一个迭代器,指向新增节点  
    }

    调整RB-tree

      在将节点插入到RB-tree中后,需要调整RB-tree使之恢复平衡,调用_rb_tree_rebalance()

    // 全局函数  
    // 重新令树形平衡(改变颜色及旋转树形)  
    // 参数一为新增节点,参数二为根节点root  
    inline void _rb_tree_rebalance(_rb_tree_node_base* x , _rb_tree_node_base*& root)  
    {  
        x->color = _rb_tree_red;    //新节点必为红  
        while(x != root && x->parent->color == _rb_tree_red)    // 父节点为红  
        {  
            if(x->parent == x->parent->parent->left)      // 父节点为祖父节点之左子节点  
            {  
                _rb_tree_node_base* y = x->parent->parent->right;    // 令y为伯父节点  
                if(y && y->color == _rb_tree_red)    // 伯父节点存在,且为红  
                {  
                    x->parent->color = _rb_tree_black;           // 更改父节点为黑色  
                    y->color = _rb_tree_black;                   // 更改伯父节点为黑色  
                    x->parent->parent->color = _rb_tree_red;     // 更改祖父节点为红色  
                    x = x->parent->parent;  
                }  
                else    // 无伯父节点,或伯父节点为黑色  
                {  
                    if(x == x->parent->right)   // 如果新节点为父节点之右子节点  
                    {  
                        x = x->parent;  
                        _rb_tree_rotate_left(x , root);    // 第一个参数为左旋点  
                    }  
                    x->parent->color = _rb_tree_black;     // 改变颜色  
                    x->parent->parent->color = _rb_tree_red;  
                    _rb_tree_rotate_right(x->parent->parent , root);    // 第一个参数为右旋点  
                }  
            }  
            else          // 父节点为祖父节点之右子节点  
            {  
                _rb_tree_node_base* y = x->parent->parent->left;    // 令y为伯父节点  
                if(y && y->color == _rb_tree_red)    // 有伯父节点,且为红  
                {  
                    x->parent->color = _rb_tree_black;           // 更改父节点为黑色  
                    y->color = _rb_tree_black;                   // 更改伯父节点为黑色  
                    x->parent->parent->color = _rb_tree_red;     // 更改祖父节点为红色  
                    x = x->parent->parent;          // 准备继续往上层检查  
                }  
                else    // 无伯父节点,或伯父节点为黑色  
                {  
                    if(x == x->parent->left)        // 如果新节点为父节点之左子节点  
                    {  
                        x = x->parent;  
                        _rb_tree_rotate_right(x , root);    // 第一个参数为右旋点  
                    }  
                    x->parent->color = _rb_tree_black;     // 改变颜色  
                    x->parent->parent->color = _rb_tree_red;  
                    _rb_tree_rotate_left(x->parent->parent , root);    // 第一个参数为左旋点  
                }  
            }  
        }//while  
        root->color = _rb_tree_black;    // 根节点永远为黑色  
    }  
    // 左旋函数  
    inline void _rb_tree_rotate_left(_rb_tree_node_base* x , _rb_tree_node_base*& root)  
    {  
            // x 为旋转点  
            _rb_tree_node_base* y = x->right;          // 令y为旋转点的右子节点  
              x->right = y->left;  
             if(y->left != 0)  
            y->left->parent = x;           // 别忘了回马枪设定父节点  
             y->parent = x->parent;  
    
            // 令y完全顶替x的地位(必须将x对其父节点的关系完全接收过来)  
              if(x == root)    // x为根节点  
                    root = y;  
            else if(x == x->parent->left)         // x为其父节点的左子节点  
                   x->parent->left = y;  
               else                                  // x为其父节点的右子节点  
                    x->parent->right = y;  
             y->left = x;  
              x->parent = y;  
    }  
    // 右旋函数  
    inline void _rb_tree_rotate_right(_rb_tree_node_base* x , _rb_tree_node_base*& root)  
    {  
            // x 为旋转点  
            _rb_tree_node_base* y = x->left;          // 令y为旋转点的左子节点  
            x->left = y->right;  
            if(y->right != 0)  
          y->right->parent = x;           // 别忘了回马枪设定父节点  
            y->parent = x->parent;  
    
            // 令y完全顶替x的地位(必须将x对其父节点的关系完全接收过来)  
            if(x == root)  
                    root = y;  
            else if(x == x->parent->right)         // x为其父节点的右子节点  
                     x->parent->right = y;  
            else                                  // x为其父节点的左子节点  
                     x->parent->left = y;  
            y->right = x;  
              x->parent = y;  
    }

    搜寻元素

    // 寻找RBTree中是否存在键值为k的节点
    template <class Key, class Value, class KeyOfValue, class Compare, class Alloc>
    typename rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::iterator 
    rb_tree<Key, Value, KeyOfValue, Compare, Alloc>::find(const Key& k) {
      link_type y = header;        // Last node which is not less than k. 
      link_type x = root();        // Current node. 
    
      while (x != 0) 
        // key_compare是节点键值大小比较函数
        if (!key_compare(key(x), k)) 
          // 如果节点x的键值大于k,则继续往左子树查找
          y = x, x = left(x);    // 
        else
          // 如果节点x的键值小于k,则继续往右子树查找
          x = right(x);
      iterator j = iterator(y); 
      // y的键值不小于k,返回的时候需要判断与k是相等还是小于  
      return (j == end() || key_compare(k, key(j.node))) ? end() : j;
    }

    set

      所有元素都会根据元素的键值自动被排序,以RB-tree作为其底层机制,不允许通过set的迭代器来改变set的元素值,因为set的元素值就是键值,更改了元素值就会影响其排列规则,如果任意更改元素值,会严重破坏set组织,因此在定义set的迭代器时被定义成了RB-tree的const_iterator,它的键值就是实值。

      它与list相同在操作前所有的迭代器在操作后仍然有效,被操作的那个迭代器除外。

    template <class Key, class Compare = less<key>, class Alloc = allloc>
    class set {
    public:
        typedef key key_type;      //键值与实值相同
        typedef key value_type;
        typedef Compare key_compare;
        typedef Compare value_compare;
    private:
        //...
        typedef rb_tree<key_type, value_type, identify<value_type>, 
            key_compare, Alloc> rep_type;
        rep_type t;      //采用红黑树来表现set
    public:
        //...
        typedef typename  rep_type::const_iterator iterator;  //定义为const_iterator,不允许更改
    
        //...
        //以下列举出的构造函数与插入均使用insert_unique方式
        template <class InputIterator>
        set(InputIterator first, InputIterator lst)
            : t(Compare()) { t.insert_unique(first, last); }
        //...
        iterator insert(iterator position, const value_type& x) {  //其中一个插入操作版本
            typedef typename rep_type::iterator rep_iterator;
            return t.insert_unique((rep_iterator&)position, x);
        }
        //...
        void erase(iterator position) {     //其中一个版本的删除操作
            typedef typename rep_type::iterator rep_iterator;
            t.erase((rep_iterator&)position);
        }
        //...
        //在first和last的前闭后开的区间中进行二分查找第一个不小于x的值
         iterator lower_bound(const key_type& x) const {
             return t.low_bound(x);   
         }
         //在first和last的前闭后开的区间中进行二分查找第一个大于x的值
         iterator upper_bound(const key_type& x) const {
             return t.upper_bound(x);
         }
         //返回上述两种方式返回的迭代器区间
         pair<iterator, iterator> equal_range(const key_type& x) const {
             return t.equal_range(x);
         }
         //...
    };

    multiset

      与set特性完全相同,唯一差别在于它允许键值重复,因此插入操作采用的是底层机制RB-tree的insert_equal()而非insert_unique()

    map

      所有元素都会根据元素的键值自动被排序,map的所有元素都是pair,同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为元素值,map不允许两个元素拥有相同的键值,不能通过map的迭代器改变map的键值,因为map元素的键值关系到map元素的排列规则,任意改变map的元素键值会破坏map组织;但可以修正元素的实值。

      重点分析subscript操作符:

    T& operator[] (const key_type& k)  {
        return (*((insert(value_type(k, T()))).first)).second; 
    }//by reference传递,所以他为左值右值都可以

      他能被当做左值引用和右值引用

    map<string, int> simap;
    simap[string("jjhou")] = 1;    //左值运用
    int number = simap[string("jjhou")];  //右值引用
    1. 首先产生一个临时对象:value_type(k, T())
    2. 再将该元素插入到map中:insert(value_type(k, T()))
    3. 插入操作符返回一个pair,其第一个元素是迭代器指向插入妥当的新元素或插入失败(键值重复)的旧元素;下标操作符为左值引用(通常表示有新元素要添加),正好可以以“实值待填”将元素位置卡好;如果下标操作符为右值引用,通常表示键值取实值此时返回的pair的第一个元素恰指向键值符合的旧元素。(insert(value_type(k, T()))).first
    4. 第一元素是一个迭代器,提领该元素:*((insert(value_type(k, T()))).first)
    5. 获得一个map元素,由键值和实值组成,取第二元素:(*((insert(value_type(k, T()))).first)).second

    hashtable

      插入删除寻找具有常数事件,以统计为基础不需要输入元素具有随机性。

      使用hash function(散列函数)将一元素映射为“大小之可接受索引”。为了避免不同元素映射到同一位置上也就是避免碰撞,可用以下几种方法。首先引入一个额外的概念负载系数——元素个数除以表格大小,除了开链以外,负载系数都是在0~1之间。

      1.线性探测:计算出某个元素的插入位置时发现该位置已经不可用,就循序往下一次寻找可用的位置,达到尾端就绕到头部去寻找。在表格足够大并且每个元素都是独立的假设下,线性探测的最坏情况是巡访整个表格,平均情况是巡访一半的表格。但是他有一个缺点:除非新元素经过hash function直接落在#4-#7上,否则其永远不能被再用,因为#3是第一考虑的位置,因为不论新元素落在89012哪个位置最终都会落在#3上。不断解决碰撞问题,最后才得以插入成功,这就是主集团问题。

      2.二次探测:如果hash function计算出的位置为H,而该位置被占用,那我们就尝试H+1^2,H+2^2......而不像线性探测那样H+1,H+2。。。它可消除主集团问题,但是却又带来次集团问题:两个元素经hash function计算出位置相同,则插入时所探测的位置也相同。

      3.开链:在每个表格的元素中维护一个list,hash function为我们分配某一个list,我们在list上执行插入删除寻找操作,针对list的操作是一种线性操作。SGI STL以质数来设计表格大小,并将28个质数计算好放置(以53为起始,大约二倍增长,*2-1)

    hashtable的迭代器

      他必须维护与整个“buckets vector”的关系,并记录目前所指的结点,前进操作首先是目前所指结点出发,前进一个位置,由于该结点被安置于list内,所以用next可以完成前进操作,如果是list的尾端结点,就跳至下一个bucket上,指向其开头元素。他只有operator++&operator++(int),没有operator--,也就是无后退操作。

    hashtable的数据结构

    /*
        Value:节点值类型
        Key:节点的键值类型
        HashFcn:仿函数,计算hash值
        ExtractKey:仿函数,提取key值
        EqualKey:仿函数,判别键值是否相同的方法
        Alloc:空间配置器
    */
    template <class Value, class Key, class HashFcn, class ExtractKey, class EqualKey, class Alloc>
    class hashtable
    {
    public:
        typedef HashFcn hasher;
        typedef EqualKey key_equal;
        typedef size_t size_type;
    
    private:
        hasher hash;
        key_equal equals;
        ExtractKey get_key;
        
        typedef __hashtable_node<Value> node;
        typedef simple_alloc<node, Alloc> node_allocator;
        
        vector<node*, Alloc> buckets;
        size_type num_elements;
        
    public:
        size_type bucket_count() const { return buckets.size(); }
    }

      插入操作

    // 插入数据不允许重复
    pair<iterator, bool>insert_unique(const value_type& obj)
    {
        resize(num_elements + 1); // 判断表格vector是否需要重建,如果需要就重建
        return insert_unique_noresize(obj); // 插入键值,不允许重复
    }
    
    void resize(size_type num_elements_hint)//如果不需要重建表格立刻返回
    {
        const size_type old_n = buckets.size();
        if(num_elements_hint > old_n)
        {
            const size_type n=next_size(num_elements_hint);//找出下一质数,也就是最接近某数并大于某数的质数
            if(n>old_n)
            {
                vector<node*, Alloc> tmp(n, (node*)0);
                for(size_type bucket = 0; bucket < old_n; ++bucket)
                {
                    node* first = buckets[bucket];
                    while(first)
                    {
                        size_type new_bucket = bkt_num(first->val, n);//找出结点应该落在哪一个新的bucket内
                        buckets[bucket] = first->next;//令旧的bucket指向所对应的串的下一结点
                        first->next = tmp[new_bucket];//将当前节点插入新bucket内,成为其对应串的第一个结点
                        tmp[new_bucket] = first;//
                        first = buckets[bucket];//回到旧的bucket所指待处理串,准备处理下一结点
                    }
                }
                buckets.swap(tmp);
            }
        }
    }
    
    pair<iterator, bool> insert_unique_noresize(const value_type& obj)
    {
        const size_type n = bke_num(obj);
        node* first = buckets[n];
    
        for(node* cur = first; cur; cur = cur->next)
        {
            if(equals(get_key(cur->val), get_key(obj)))
            {
                return pair<iterator, bool>(iterator(cur, this), false);
            }
        }
    
        node* tmp = new_node(obj);
        tmp->next = first;
        bucklet[n] = tmp;
        ++num_elements;
        return pair<iterator, bool>(iterator(tmp, this), true);
    }
    
    // 插入数据允许重复
    iterator insert_equal(const value_type& obj)
    {
        resize(num_elements + 1); // 判断表格vector是否需要重建,如果需要就重建
        return insert_equal_noresize(obj); // 插入键值,允许重复
    }
    
    iterator insert_equal_noresize(const value_type& obj)
    {
        const size_type n = bke_num(obj);
        node* first = buckets[n];
    
        for(node* cur = first; cur; cur = cur->next)
        {
            if(equals(get_key(cur->val), get_key(obj)))
            {
                // 如果有key相同的节点,将新节点插入在相同节点的后面
                node* tmp = new_node(obj);
                tmp->next = cur->next;
                cur->next = tmp;
                ++num_elements;
                return iterator(tmp, this);
            }
        }
        node* tmp = new_node(obj);
        tmp->next = first;
        bucklet[n] = tmp;
        ++num_elements;
        return iterator(tmp, this);
    }
    // 映射函数
    size_type bkt_num(const value_type& obj, size_t n) const
    {
        return bkt_num_key(get_key(obj), n);
    }
    
    size_type bkt_num(const value_type& obj) const
    {
        return bkt_num_key(get_key(obj));
    }
    
    size_type bkt_num_key(const key_type& key) const
    {
        return bkt_num_key(get_key(obj), buckets.size());
    }
    
    // 最底层干活的函数
    size_type bkt_num_key(const key_type& key, size_t n) const
    {
        // STL为所有的基础类型都定义了hash函数
        return hash(key) % n;
    }

      在调用clear清除时,只是把bucket内容为nullptr,并未释放bucket vector的空间。

    hash function

      stl内建哈希函数,针对char、short、long、int这些类型只是简单的返回其数值,但是对于char*会调用以下版本hash(stl内建的只有只几种类型和其unsigned版本)

    inline size_t __stl_hash_string(const char* s)
    {
        unsigned long h = 0;
        for( ;*s;++s)
            h = 5*h + *s;
        return size_t(h);
    }

    hash_set

      hash_set无自动排序功能。其余与set相同。

    template <class Value, class HashFcn = hash<Value>,
        class EqualKey = equal_to<Value>,
        class Alloc = alloc>
        class hash_set
    {
    private:
        // 底层为hashtable
        typedef hashtable<Value, Value, HashFcn, identity<Value>, EqualKey, Alloc> ht;
        ht rep;
    
    public:
        typedef typename ht::key_type key_type;
        typedef typename ht::value_type value_type;
        typedef typename ht::hasher hasher;
        typedef typename ht::key_equal key_equal;
    
        typedef typename ht::size_type size_type;
        typedef typename ht::difference_type difference_type;
        typedef typename ht::const_pointer pointer;
        typedef typename ht::const_pointer const_pointer;
        typedef typename ht::const_reference reference;
        typedef typename ht::const_reference const_reference;
    
        typedef typename ht::const_iterator iterator;
        typedef typename ht::const_iterator const_iterator;
    
        hasher hash_funct() const { return rep.hash_funct(); }
        key_equal key_eq() const { return rep.key_eq(); }
    
    public:
        // 默认构造100大小的hashtable,将会被调整为大于100的预定义质数
        hash_set() : rep(100, hasher(), key_equal()) {}
        explicit hash_set(size_type n) : rep(n, hasher(), key_equal()) {}
        hash_set(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {}
        hash_set(size_type n, const hasher& hf, const key_equal& eql)
            : rep(n, hf, eql) {}
    
        // 所有的插入操作都是insert_unique,不允许键值重复
        template <class InputIterator>
        hash_set(InputIterator f, InputIterator l)
            : rep(100, hasher(), key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_set(InputIterator f, InputIterator l, size_type n)
            : rep(n, hasher(), key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_set(InputIterator f, InputIterator l, size_type n,
            const hasher& hf)
            : rep(n, hf, key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_set(InputIterator f, InputIterator l, size_type n,
            const hasher& hf, const key_equal& eql)
            : rep(n, hf, eql) {
            rep.insert_unique(f, l);
        }
    
    public:
        // 所有操作几乎都是直接调用hashtable的接口
        size_type size() const { return rep.size(); }
        size_type max_size() const { return rep.max_size(); }
        bool empty() const { return rep.empty(); }
        void swap(hash_set& hs) { rep.swap(hs.rep); }
        friend bool operator== __STL_NULL_TMPL_ARGS(const hash_set&,
            const hash_set&);
    
        iterator begin() const { return rep.begin(); }
        iterator end() const { return rep.end(); }
    
    public:
        pair<iterator, bool> insert(const value_type& obj)
        {
            pair<typename ht::iterator, bool> p = rep.insert_unique(obj);
            return pair<iterator, bool>(p.first, p.second);
        }
    #ifdef __STL_MEMBER_TEMPLATES
        template <class InputIterator>
        void insert(InputIterator f, InputIterator l) { rep.insert_unique(f, l); }
    #else
        void insert(const value_type* f, const value_type* l) {
            rep.insert_unique(f, l);
        }
        void insert(const_iterator f, const_iterator l) { rep.insert_unique(f, l); }
    #endif /*__STL_MEMBER_TEMPLATES */
        pair<iterator, bool> insert_noresize(const value_type& obj)
        {
            pair<typename ht::iterator, bool> p = rep.insert_unique_noresize(obj);
            return pair<iterator, bool>(p.first, p.second);
        }
    
        iterator find(const key_type& key) const { return rep.find(key); }
    
        size_type count(const key_type& key) const { return rep.count(key); }
    
        pair<iterator, iterator> equal_range(const key_type& key) const
        {
            return rep.equal_range(key);
        }
    
        size_type erase(const key_type& key) { return rep.erase(key); }
        void erase(iterator it) { rep.erase(it); }
        void erase(iterator f, iterator l) { rep.erase(f, l); }
        void clear() { rep.clear(); }
    
    public:
        void resize(size_type hint) { rep.resize(hint); }
        size_type bucket_count() const { return rep.bucket_count(); }
        size_type max_bucket_count() const { return rep.max_bucket_count(); }
        size_type elems_in_bucket(size_type n) const
        {
            return rep.elems_in_bucket(n);
        }
    };

    hash_map

    template <class Key, class T, class HashFcn = hash<Key>,
        class EqualKey = equal_to<Key>,
        class Alloc = alloc>
        class hash_map
    {
    private:
        // 底层为hashtable
        typedef hashtable<pair<const Key, T>, Key, HashFcn, select1st<pair<const Key, T> >, EqualKey, Alloc> ht;
        ht rep;
    
    public:
        typedef typename ht::key_type key_type;
        typedef T data_type;
        typedef T mapped_type;
        typedef typename ht::value_type value_type;
        typedef typename ht::hasher hasher;
        typedef typename ht::key_equal key_equal;
    
        typedef typename ht::size_type size_type;
        typedef typename ht::difference_type difference_type;
        typedef typename ht::pointer pointer;
        typedef typename ht::const_pointer const_pointer;
        typedef typename ht::reference reference;
        typedef typename ht::const_reference const_reference;
    
        typedef typename ht::iterator iterator;
        typedef typename ht::const_iterator const_iterator;
    
        hasher hash_funct() const { return rep.hash_funct(); }
        key_equal key_eq() const { return rep.key_eq(); }
    
    public:
        // 默认构造100大小的hashtable,将会被调整为大于100的预定义质数
        hash_map() : rep(100, hasher(), key_equal()) {}
        explicit hash_map(size_type n) : rep(n, hasher(), key_equal()) {}
        hash_map(size_type n, const hasher& hf) : rep(n, hf, key_equal()) {}
        hash_map(size_type n, const hasher& hf, const key_equal& eql)
            : rep(n, hf, eql) {}
            
        // 所有的插入操作都是insert_unique,不允许键值重复
        template <class InputIterator>
        hash_map(InputIterator f, InputIterator l)
            : rep(100, hasher(), key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_map(InputIterator f, InputIterator l, size_type n)
            : rep(n, hasher(), key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_map(InputIterator f, InputIterator l, size_type n,
            const hasher& hf)
            : rep(n, hf, key_equal()) {
            rep.insert_unique(f, l);
        }
        template <class InputIterator>
        hash_map(InputIterator f, InputIterator l, size_type n,
            const hasher& hf, const key_equal& eql)
            : rep(n, hf, eql) {
            rep.insert_unique(f, l);
        }
    
    public:
        size_type size() const { return rep.size(); }
        size_type max_size() const { return rep.max_size(); }
        bool empty() const { return rep.empty(); }
        void swap(hash_map& hs) { rep.swap(hs.rep); }
        friend bool
            operator== __STL_NULL_TMPL_ARGS(const hash_map&, const hash_map&);
    
        iterator begin() { return rep.begin(); }
        iterator end() { return rep.end(); }
        const_iterator begin() const { return rep.begin(); }
        const_iterator end() const { return rep.end(); }
    
    public:
        pair<iterator, bool> insert(const value_type& obj)
        {
            return rep.insert_unique(obj);
        }
    #ifdef __STL_MEMBER_TEMPLATES
        template <class InputIterator>
        void insert(InputIterator f, InputIterator l) { rep.insert_unique(f, l); }
    #else
        void insert(const value_type* f, const value_type* l) {
            rep.insert_unique(f, l);
        }
        void insert(const_iterator f, const_iterator l) { rep.insert_unique(f, l); }
    #endif /*__STL_MEMBER_TEMPLATES */
        pair<iterator, bool> insert_noresize(const value_type& obj)
        {
            return rep.insert_unique_noresize(obj);
        }
    
        iterator find(const key_type& key) { return rep.find(key); }
        const_iterator find(const key_type& key) const { return rep.find(key); }
    
        T& operator[](const key_type& key) {
            return rep.find_or_insert(value_type(key, T())).second;
        }
    
        size_type count(const key_type& key) const { return rep.count(key); }
    
        pair<iterator, iterator> equal_range(const key_type& key)
        {
            return rep.equal_range(key);
        }
        pair<const_iterator, const_iterator> equal_range(const key_type& key) const
        {
            return rep.equal_range(key);
        }
    
        size_type erase(const key_type& key) { return rep.erase(key); }
        void erase(iterator it) { rep.erase(it); }
        void erase(iterator f, iterator l) { rep.erase(f, l); }
        void clear() { rep.clear(); }
    
    public:
        void resize(size_type hint) { rep.resize(hint); }
        size_type bucket_count() const { return rep.bucket_count(); }
        size_type max_bucket_count() const { return rep.max_bucket_count(); }
        size_type elems_in_bucket(size_type n) const
        {
            return rep.elems_in_bucket(n);
        }
    };
  • 相关阅读:
    基础知识
    显示功能
    监听器
    检测session是否为空
    W7-Web服务器[JavaWeb]
    D9-哈希表[Java数据结构和算法]
    D8-查找算法[Java数据结构和算法]
    D7-排序算法(三)[Java数据结构和算法]
    W6-junit、泛型、枚举、增强for、可变参数、反射[JavaWeb]
    D6-排序算法(二)[Java数据结构和算法]
  • 原文地址:https://www.cnblogs.com/tianzeng/p/12595061.html
Copyright © 2020-2023  润新知