序列式容器

目录

  • 容器结构分类
  • 通过萃取机traits萃取迭代器的型别
  • 容器list
    • list的定义
    • list的node定义
    • list的iterator
  • 容器vector
    • vector的定义
    • vector的iterator
    • vector 的大小
  • array
    • array的定义
  • forward_list
    • forward_list与list的区别
  • deque
    • deque的定义
    • deque的iterator

容器结构分类

这里的衍生,并非继承关系,而是一种包含关系。
例如heap中包含一个vector。

通过萃取机traits萃取迭代器的型别

template <class I>
struct iterator_traits { //traits是特性之意
    typedef typename I::value_type value_type;
};
//两个偏特化(partial specialization)
template <class T>
struct iterator_traits<T*> {
    typedef T value_type;
};
template <class T>
struct iterator_traits<const T*> {
    typedef T value_type; //注意是T而不是const T,因为value_type的主要目的是用来声明变量,而声明一个无法被赋值的变量是没有什么用的(const T),所以要去掉const
};
//于是当需要知道I的value_type时,便可以这么写:
template<typename I>
void algorithm(...) {
    typename iterator_traits<I>::value_type v1;
}

容器list

list在要内存时,不光需要一个指针,还需要指向前后的两个指针。

list的定义

//list的定义
    template<class T, class Alloc = alloc>
    class list {
    protected:
        typedef __list_node<T> list_node;
    public:
        typedef list_node* link_type;
        //G2.9编译器的iterator
        typedef __list_iterator<T, T&, T*> iterator;
        //G4.9编译器的iterator
        typedef _List_iterator<_Tp> iterator;
    portected:
        link_type node;
    };

list的node定义

G2.9编译器的设计是如下所示:其中前向指针和后向指针,指向的都是void类型,所以sizeof(list)是4个字节,就是一个指向数据的指针。

//list节点的定义
    template <class T>
    struct __list_node {
        typedef void* void_pointer;
        void_pointer prev;
        void_pointer next;
        T data;
    };

G4.9版本在G2.9版本的基础之上,将node部分拆分成了两个部分,一个是_list_node_base,改变了G2.9版本的前向和后向指针的指向类型,另外node是继承_List_node_base后,再加上数据部分,如下所示:

//G4.9编译器,list节点的定义:
    struct _List_node_base {
        _List_node_base* _M_next;
        _List_node_base* _M_prev;
    };
    template<typename _Tp>
    struct _List_node : public _List_node_base {
        _Tp _M_data;
    };

list的iterator

list的存储是非连续空间,所以list的iterator不能是普通指针。而是定义一个class来模拟指针,称之为smart pointer


如上图红色的泡泡,当list的iterator加一时,应该指向下一个节点的位置。所以list的iterator是一个smart pointer.
每个iterator要有5个typedef,因为迭代器是容器和算法之间的桥梁,所以迭代器必须定义这五种typedef,以便于回答算法的提问:
传入类型T的参数,直接T::iterator_category,就可以得到迭代器的类型。

  • iterator_category
  • value_type
  • difference_type
  • pointer
  • reference
    list的五个reference如下所示:
//list的五个typedef定义
template<typename _TP>
struct _List_iterator {
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef _Tp value_type;
    typedef _Tp* pointer;
    typedef _Tp& reference;
    typedef ptrdiff_t difference_type;
};

还有一大堆的操作符重载。

//list的iterator的定义
    template <typename _Tp>
    struct _List_iterator {
        typedef _Tp* poinetr;
        typedef _Tp& reference;
    };

容器vector

vector的扩充方式是两倍增长,换一个内存后进行两倍增长。

vector的定义

//vector的定义
template <class T,class Alloc = alloc>
class vector{
public:
    typedef T value_type;
    typedef value_type* iterator;//T*
    typedef value_type& reference;
    typedef size_t size_type;
protected:
    iterator start;
    iterator finish;
    iterator end_of_storage;
public:
    iterator begin() { return start; }
    iterator end() { return finish; }
    size_type size() const { //大小 finish-start
        return size_type(end() - begin());
    }
    size_type capacity() const { //容量
        return size_type(end_of_storage - begin());
    }
    bool empty() const { return begin() == end(); }
    reference operator[](size_type n) { //连续空间的中括号
        return *(begin() + n);
    }
    reference front() { return *begin(); } //取出首个元素
    reference back() { //取出尾部元素
        return *(end() - 1);
    }
}

vector的iterator

//vector的迭代器设计
template <class T, class Alloc = alloc>
class vector {
public:
    typedef T value_type;
    typedef value_type* iterator; //T*
};
vector<int>vec;
vector<int>::iterator ite = vec.begin();

vector 的大小

vector的大小是三个指针,start,finish,end_of_storage,这三个指针的大小是12.

array

array的定义

//array的定义
template <typename _Tp, std::size_t _Nm>
struct array{
    typedef _Tp value_type;
    typedef _Tp* pointer;
    typedef value_type* iterator;

    //支持0大小的数组生成
    value_type _M_instance[_Nm ? _Nm : 1];

    iterator begin() {
        return iterator(&_M_instance[0]);
    }
    iterator end() {  //最后一个元素的下一个元素
        return iterator(&_M_instance[_Nm]);
    }
};

forward_list

forward_list与list的区别

单向链表与list的区别仅仅只在于一个是单向,一个是双向,其他都是相同的。

deque

deque是一个双向开口的连续线性空间,其实是动态的以分段连续空间组合而成 ,外界以为它是连续的。

deque是由一段一段定量的连续空间构成,一旦有必要在deque的前端或后端增加新空间时,便配置一段定量的连续空间,串接在整个deque的头端或尾端,deque的最大任务就是在这些分段的定量连续空间上,维护其整体连续的假象,并提供随机存取的接口,避开了“重新配置、复制、释放”的轮回,代价则是复杂的迭代器架构。

如上图所示,deque管理一个map(一小块连续空间),map是一个vector,其中每个元素是一个指针,指向另一段较大的连续线性空间,称为缓冲区。

deque的定义

//一个deque的大小是40个字节

template <class T,class Alloc = alloc, size_t BufSiz = 0> //BufSizs是buffer的大小
class deque {
public:
    typedef T value_type;
    typedef __deque_iterator<T, T&, T*, BufSiz>iterator;
protected:
    typedef pointer* map_pointer; //T**
protected:
    iterator start; //大小是16个字节
    iterator finish; //大小是16个字节
    map_pointer map; //控制中心是个vector,是会2倍动态增长的 T** 指向指针的指针 大小是4
    size_type map_size; //大小是4字节
public:
    iterator begin() { return start; }
    iterator end() { return finish; }
    iterator size() const { return finish - start; }
};

deque的iterator

deque的迭代器包含四个部分:cur first last node

//deque的iterator
template <class T, class Ref, class Ptr,size_t BufSiz>
struct __deque_iterator {
    typedef random_access_iterator_tag  iterator_category;
    typedef T value_type;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef T** map_pointer;
    typedef __deque_iterator self;

    T* cur;
    T* first;
    T* last;
    map_pointer node;

};

原文地址:https://www.cnblogs.com/ccpang/p/12248323.html

时间: 2024-11-08 12:18:36

序列式容器的相关文章

C++ STL序列式容器优缺点记录

STL中有三种序列式容器vector,list,deque.对其分别进行性能介绍 vector: vector内部是通过连续的动态内存空间(dynamic array)去管理的,每push_back一个元素,将安插到array尾部. 这种通过连续的内存空间去管理的方式,可以方便我们去通过下标索引到值,在其尾部的插入和删除效率都非常之高. 当在vector内部去进行插入和删除则会导致vector容器元素去移动位置,因此效能较差 deque: deque是一个双端队列,可在首尾进行元素的插入和删除.

STL学习笔记(序列式容器)

Vector Vector是一个动态数组. 1.Vector的操作函数 构造.拷贝和析构 vector<Elem> c //产生一个空vector ,其中没有任何元素 vector<Elem> c1(c2) //产生另一个同型vector的副本,(所有元素都被拷贝) vector<Elem> c(n) //利用元素的default构造函数生成一个大小为n的vector vector<Elem> c(n,elem) //产生一个大小为n的vector,每个元素

stl源码剖析-序列式容器 之 vector

vector的数据安排以及操作方式,与array(c++自身提供的序列式容器)非常相似.两者唯一的差别在于空间的运用的灵活性.array是静态空间,一旦配置了将不能随意更改其大小,若要更改需要重新配置一块新的空间,如何将元素从旧址中一一搬迁,再释放原来的系统.而vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间已容纳新元素.(实际vector每次动态分配的空间大小是有限的,超过了这个临界值同样是要像array一样进行元素搬迁,下面将会进行详细介绍)vector 是最常用的 C++

Ch4 序列式容器(下)

4.7 heap(隐式表述:implicit representation) 4.7.1 heap概述 binary max heap作为priority queue的底层机制,原因是: binary heap:完全二叉树的结构可以保证整棵树没有节点漏洞,用array来表示这棵树的时候,只需要从array[1]开始保存(#0元素设为无限大或无限小),那么位于array第i个的节点,其左子节点就是第2*i个,右子节点是第2*i+1个,父节点是第i/2(向下取整)个.--这种以array表述tree

《STL源码剖析》读书笔记之序列式容器(3)

1.heap heap不属于STL容器组件,它是priority queue的底层实现机制. (1)push_heap算法 向堆中加入元素,首先将要加入的元素放到堆所在数组的末端,然后再对这个元素进行上溯操作,直到新堆合法为止.如下图所示: (2)pop_heap算法 pop_heap操作取走堆中的最大(小)值.根据堆的特性,堆的最大(小)值必定是堆所存数组的第一个元素.取堆的最大(小)元素时,将堆的最后一个元素和堆的第一个元素互换,然后再对第一个元素进行下溯操作,直到新堆满足堆的定义.下图给出

序列式容器————vector

目录 介绍 1 创建 2 容量和大小 size() capacity() 3 resize() 4 reverse() 5 获取元素 front() back() 6 迭代器(待补充) 7 push_back() 8 emplace_back() 9 emplace()(待补充) 10 insert() 11 clear() 12 remove() 13 pop_back() 14 shrink_to_fit() 15 erase() 介绍 和 array<T,N> 容器相似,不同的是 vec

STL浅析——序列式容器vector的构造和内存管理: constructor() 和 push_back()

咱们先来做一个测试capacity是容器容量,size是大小: #include <iostream> #include <vector> using namespace std; int main(){ vector<int> result; for (int i = 0; i < 17; i++) { result.push_back(i); printf("element count: %d\t", result.size()); pri

《STL源码解析》读书笔记之序列式容器(2)

1.deque deque和vector的最大差异在于deque允许在常数时间内对首端进行元素的插入和删除操作.而且deque没有容量的观念,因为它是动态地以分段连续空间组合而成的,随时可以增加一段新的空间并链接起来.像vector那样因旧空间不足而重新配置一块更大空间的情况在deque里是不会发生的.虽然deque也提供Random Access Iterator,但它的迭代器并不是普通指针,这影响了很多操作的效率. (1)deque的map deque在逻辑上是连续空间,但实际上它是由一段一

《STL源码剖析》学习笔记-第4章 序列式容器

1.vector 1.vector特性 (1)vector有自动扩容操作,每次扩容伴随着"配置新空间 / 移动旧数据 / 释放旧空间"的操作,因此有一定时间成本. (2)vector提供了reserve接口,如果能够对元素个数有大概了解,可以一开始就分配合适的空间. (3)vector的内存空间是连续的,对插入元素的操作而言,在vector尾部插入才是合适的选择.维护的是一个连续线性空间,所以vector支持随机存取. (4)vector动态增加大小时,并不是在原空间之后持续新空间(无

stl源码剖析-序列式容器 之 list

较久以前学过数据结构,对链表的定义和行为结构有过了解,所以阅读源码学习stl定义的list容器的并不算吃力. list与vector都是两个常用的容器,与vector不同,list不是连续线性空间的,list是一个双向链表.每次插入或者删除一个元素,将配置或者释放一个元素空间,因此,list对于空间的运用有着绝对的精准,不会造成浪费现象.而且对于任何位置的元素插入或者删除,其操作时间永远是常数时间.(缺点是不能进行随机的访问) list节点 list链表本身和list节点是分开设计的,以下是li