C++笔记八(Boolan网——STL与泛型编程)

2017-06-03  本文已影响0人  小小出大炮

本周内容:
(1)deque&queue 和 stack 深度探索
(2)R-B tree 深度探索
(3)set/multiset深度探索
(4)map/multimap深度探索
(5)hashtable深度探索
(6)unordered容器概念

一 deque&queue 和 stack 深度探索

deque:deque的内存空间分布是小片的连续,小片间用链表相连,实际上内部有一个map的指针。其中buffer表示deque的缓冲区,每个buffer可以存放多个元素结点。并且每个buffer指针存放在vector容器中。每个iterator存放四个指针:cur、first、last、node,cur表示当前数据结点的指针,first表示buffer首指针,last表示buffer的尾指针,node表示这个iterator在vector中的指针地址。它模拟了一个连续的存储空间(实质表示连续分段的容器)。


deque.png

deque实现代码如下,gnu2.9模板参数有三个,其中第三个BufSiz默认为0,可以由使用者自定buffer大小。


deque代码.png
同样的,deque的iterator需要回答算法的五个问题,即上周的iterator traits。
deque iterator.png
//在position处安插一个元素,其值为x
iterator insert(iterator position,const value_type& x){
    if(position.cur == start.cur){               //如果安插点是deque最前端
      push_front(x);                                //交给push——front()做
      return start;
    }
    else if (position.cur == finish.cur) {    //如果安插点是deque最尾端
      push_back(x);                              //交给push——back()做
      iterator tmp =finish;
      --tmp;
      return tmp;
    }
    else {
      return insert_aux(position,x);
    }
  }

template<class T,class Alloc,size_t BufSize>
typename deque<T,Alloc,BufSize>::iterator
deque<T,Alloc,BufSize>::insert_aux(iterator pos,const value_type& x){
    difference_type index = pos - start;     //安插点之前的元素个数
    value_type x_copy =x;
    if (index<size()/2){                //如果安插点之前的元素个数较少
      push_front(front());             //在最前端加入与第一元素同值的元素
      ...
      copy(front2,pos1,front1);    //元素搬移
    }
    else{                        //安插点之后的元素个数较少
      push_back(back());   //在尾端加入与最末元素同值的元素
      ...
      copy_backward(pos,back2,back1);      //元素搬移
    }
    *pos = x_copy;        //在安插点上设定新值
    return pos;
}

deque是如何模拟连续空间的呢?全都是deque iterators的功劳,源代码做了大量的操作符重载,尤其是遇到buffer边界时如何跳到控制中心,使得deque的iterator能够在buffer之间模拟出连续空间。实现代码如下:

reference operator[] (size_type n)
{
    return start[difference_type(n)];
}
reference front(){return *start;}
reference back()
{
    iterator tmp = finish;
    --tmp;
    return *tmp;
}
size_type size() const {return finish - start;}
bool empty() const {return == start;}
reference operator*() const {return *cur;}
pointer operator->() const {return & (operator*());}
//两根iterators之间的距离相当于
//(1)两根iterators间的buffers的总长度+
//(2)itr至其buffer末尾的长度+
//(3)x至其buffer起头的长度
difference_type
operator-(const self& x) const
{
     return difference_type(buffer_size())*(node-x.node-1)+
        (cur-first)+(x.last-x.cur);
          //首尾buffers之间的buffers数量
          //(cur-first)末尾(当前)buffer的元素量,(x.last-x.cur)起始buffer的元素量
}
deque模拟连续空间.png
deque模拟连续空间2.png
deque模拟连续空间3.png

queue和stack底层都是由deque完成的,通常他们也被称为容器适配器。

二 R-B tree 深度探索

rb_tree.png
rb_tree使用.png

红黑树的使用如下:


rb_tree使用.png

三 set/multiset深度探索

四 map/multimap深度探索

五 hashtable深度探索

有一大堆的东西要放在容器里,每一个东西可以折射成一个数值,这些数值的变化如果有2^32种变化,所需要的空间要非常大,hashtable就是用来解决这个问题。


hashtable.png

当碰撞的元素超过“篮子”的个数,经验判断为危险,则将“篮子”的数量扩大为原来的两倍,一般篮子数量是素数。GUC初始篮子数量为53,两倍变成106,附近的素数而且比106大的为193.
我们可以使用hashtable iterators改变元素的data,但不能改变元素的key(因为hashtable根据key实现严谨的元素排列)。


hashtable.png
hashtable源代码如下:
hashtable.png

第一第二个参数与红黑树为底层的set和map类似,第三个模板参数hashFcn的目的是希望根据元素值算出一个hash code(一个可进行modulus运算的值),使得元素hash code映射之后能够够杂乱够随机地被置于hashtable内,越是乱,越是不容易碰撞,可以传函数、仿函数、函数对象,它是通过模板偏特化实现,c风格的字符串char*是一个指针,stl提供了实现方式,而C++的字符串string则需要自己写实现方式;第四个ExtractKey告诉我们如何取出key;第五个EqualKey告诉我们如何比较key大小;第六个分配器。

六 unordered容器概念

从C++11开始,以hash开头的容器都改为unordered容器(不定序容器)

上一篇下一篇

猜你喜欢

热点阅读