• STL学习笔记--序列式容器


    1、vector

    vector是一个线性顺序结构。相当于数组,但其大小可以不预先指定,并且自动扩展。故可以将vector看作动态数组。
    在创建一个vector后,它会自动在内存中分配一块连续的内存空间进行数组存储,初始的空间大小可以预先指定也可以由vector默认指定,这个大小即capacity()函数的返回值,当存储的数据超过分配的空间时,vector会重新分配一块内存。
    重新分配内存的动作:
    (1)申请一块更大的内存
    (2)将原来的数据复制到新的内存块中
    (3)销毁掉原内存块中的对象
    (4)释放原来的内存空间
    但重新分配内存是很耗时的,会导致糟糕的性能,而且一旦内存重新分配,和vector元素相关的references,pointers,iterators都会失效。
    所以vector性能优异的秘诀是:配置比其所容纳的元素更多的内存。
    1)使用reserve()保留适当容量,避免一再重新配置内存。
    2)如果预先知道vector可能容纳元素的多少,在创建vector时就指定其空间大小。

    //使用reserve申请适当的内存,仅分配内存,size()的大小不变
    vector<int> v; //create an empty vector
    v.reserve(80);// reserve memory for 80 elements
    
    //在创建vector时指定空间大小,这种方式要调用构造方法,如果只是为了保留足够的内存
    //建议使用上面的reserve方法
    //create a vector and call 80 times the default constructor
    vector<int> v(80); 
    

    vector的特点:

    (1)元素连续存储,空间可以动态扩展。
    (2)可以随机访问,像数组一样被访问,即支持[]操作符和vector.at()。
    (3)在末端增加和删除元素性能较好,在内部进行插入、删除操作效率非常低。
    (4)vevtor的迭代器是随机存储迭代器,可以操作所有的STL算法。
    (5)只能在vector的最后进行push pop操作。

    vector的一些使用技巧:
    (1)vector的clear()方法并不会释放vector所申请的内存,只是清除了存储在vector中的元素,capacity的大小并不会变。

    const int MAX_NUM = 1000;
    vector<int> v;
    for (int i = 0; i < MAX_NUM; i++)
    {
    	v.push_back(i);
    }
    cout << "Before Clear:
    ";
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    v.clear(); //并不会释放vector占用的内存,即capacity的大小不变
    //v.swap(vector<int>());
    cout << "After Clear:
    ";
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    

    clear_vector

    要想彻底释放vector占用的内存,可以采用swap方法实现:

    v.swap(vector<int>());
    

    采用swap后的效果:
    swap_vector

    (2)缩减vector的容量到合适(shrink to fit)。
    有时候经过一系列的操作,vector的元素个数终将稳定,但可能vector的容量还是很大,为了节约内存,可采取下面的操作使vector的容量缩减至合适。
    两个vector交换内容后,两者的容量也会交换,下面的例子虽然保留了元素,却缩减了容量。

    const int MAX_NUM = 1000;
    vector<int> v;
    for (int i = 0; i < MAX_NUM; i++)
    {
    	v.push_back(i);
    }
    cout << "Before Clear:
    ";
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    //
    vector<int>::iterator iter = std::find(v.begin(),v.end(),100);
    if (iter != v.end())
    {
    	v.erase(iter,v.end());
    }
    
    cout << "
    After a series of operators:
    ";
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    
    //shrink to fit 缩减容量
    vector<int>(v).swap(v);
    
    
    cout << "
    After shrink to fit:
    ";
    cout << "size:" << v.size() << endl;
    cout << "capacity:" << v.capacity() << endl;
    

    shrink_to_fit


    2、deque

    deque也采用动态数组来管理元素,提供随机存储。和vector不同的是,deque的动态数组头尾都开放,能做在头尾两端进行快速安插和删除。
    deque采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的追踪。

    deque的特点:
    (1) 两端都能快速安插元素和移除元素(vector只能在尾端)

    deque<int> d;
    const int _MAX = 6;
    for (int val = 0; val < _MAX; val++)
    {
    	d.push_back(val);
    	d.push_front(val);
    }
    std::copy(d.begin(), d.end(),std::ostream_iterator<int>(cout," "));
    

    (2) deque不支持对容量和内存重分配时机的控制。无capacityreserve操作。deque的内存重分配优于vector,不必在内存重分配时复制所有的元素。
    (3) 和vector一样在中间部分安插、移除元素的速度相对较慢。

    3、list

    list使用一个doublely linked list(双向链表)来管理元素。它的数据由若干个节点构成,每一个节点都包含一个信息块(实际数据)、一个前驱指针和一个后驱指针。list使用的是非连续的内存空间。

    list与vector、deque的区别:
    (1) list不支持随机存取。由于内部结构的原因,list的随机检索性能低下,检索时间与目标元素位置成正比。
    (2) 任何位置(不只是两端)执行元素的安插和移除都非常快,始终是常数时间内完成。
    (3) 安插与删除并不会造成指向其它元素的各个pointers、references、iterators失效。
    (4) list未提供容量、空间重新分配等操作,因为没有必要,每个元素都有自己的内存,在被删除之前一直有效。
    (5) list提供了不少特殊的成员函数,专门用于移动元素。较之同名的STL通用算法,效率更高。
    如: sort() remove() remove_if()

    //list的移除操作和排序
    cout << "list test:
    ";
    list<int> list1;
    for (int val = 1; val < 5; val++)
    {
    	list1.push_back(val);
    	list1.push_front(val);
    }
    std::copy(list1.begin(), list1.end(),std::ostream_iterator<int>(cout," "));
    
    int remove_element = 4;
    cout << "
    Remove [" << remove_element <<"]:" << endl;
    list1.remove(remove_element); //移除元素4
    std::copy(list1.begin(), list1.end(),std::ostream_iterator<int>(cout," "));
    
    cout << "
    Sort:" << endl;
    list1.sort(std::greater<int>()); //降序排列
    std::copy(list1.begin(), list1.end(),std::ostream_iterator<int>(cout," "));
    
    //vector的移除元素和排序操作
    cout << "
    vector test:
    ";
    vector<int> v;
    for (int val = 1; val < 5; val++)
    {
    	v.push_back(val);
    	v.push_back(val + 1);
    }
    std::copy(v.begin(), v.end(),std::ostream_iterator<int>(cout," "));
    
    //移除元素 1
    int ele = 1;
    cout << "
    After Remove [" << ele <<"]:
    ";
    v.erase(std::remove(v.begin(),v.end(),ele),v.end());//删除元素操作
    std::copy(v.begin(), v.end(),std::ostream_iterator<int>(cout," "));
    
    //排序
    cout << "
    Sort:
    ";
    std::sort(v.begin(),v.end(),std::greater<int>()); //降序排列
    std::copy(v.begin(), v.end(),std::ostream_iterator<int>(cout," "));
    

    list_remove_pic

    4、vector,deque,list三者比较

    vector是一段连续的内存块,而deque是多个连续的内存块, list是所有元素分开保存

    vector的查询性能最好,并且在末端增加数据也很高效,除非它重新分配内存。vector适合高效的随机存储

    list是一链表,任何一个元素都可以是不连续的,它有一个前驱指针和一个后驱指针。所以list对元素的插入、删除的性能最好。list适合大量地插入和删除操作而不关心随机存储的需求

    deque介于两者之间,是对vector和list优缺点的结合,是处于两者之间的一种容器。如果需要随机存取又关心两端数据的插入和删除,deque是最佳之选。

  • 相关阅读:
    14.4.2 Change Buffer 延迟写
    14.4.1 Buffer Pool
    如何围绕业务特性,做企业信息化?
    如何围绕业务特性,做企业信息化?
    14.3 InnoDB Multi-Versioning InnoDB 多版本
    14.2 InnoDB and the ACID Model
    14.1.3 检查InnoDB 可用性:
    14.1.2 InnoDB表最佳实践:
    14.1.1 使用InnoDB 表的好处:
    7.5.1 Point-in-Time Recovery Using Event Times 使用Event Times 基于时间点恢复
  • 原文地址:https://www.cnblogs.com/cmranger/p/4715377.html
Copyright © 2020-2023  润新知