序列式容器

    默认数据无序排列,但可排序操作

STL提供三个序列式容器

  • vector
  • deque
  • list

*可将strings和array当作序列式容器,但strings和array不属于STL容器。

vector

参考

  • http://www.cplusplus.com/reference/vector/vector/

    vector是表示可以动态改变大小的数组的序列容器。

构造函数

default (1)

explicit vector (const allocator_type& alloc = allocator_type());

fill (2)

explicit vector (size_type n); vector (size_type n, const value_type& val, const allocator_type& alloc = allocator_type());

range (3)

template <class InputIterator> vector (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());

copy (4)

vector (const vector& x);vector (const vector& x, const allocator_type& alloc);

move (5)

vector (vector&& x);vector (vector&& x, const allocator_type& alloc);

initializer list (6)

vector (initializer_list<value_type> il, const allocator_type& alloc = allocator_type());

// 默认allocator为alloc, 其具体使用版本请参照<stl_alloc.h>  
template <class T, class Alloc = alloc>  
class vector  
{  
public:  
  // 标记为'STL标准强制要求'的typedefs用于提供iterator_traits<I>支持  
  typedef T value_type;                         // STL标准强制要求  
  typedef value_type* pointer;                  // STL标准强制要求  
  typedef const value_type* const_pointer;  
  // 由于vector的特性, 一般我们实作的时候都分配给其连续的内存空间,  
  // 所以其迭代器只需要定义成原生指针即可满足需要  
  typedef value_type* iterator;                 // STL标准强制要求  
  typedef const value_type* const_iterator;  
  typedef value_type& reference;                // STL标准强制要求  
  typedef const value_type& const_reference;  
  typedef size_t size_type;  
  typedef ptrdiff_t difference_type;            // STL标准强制要求  
  
protected:  
  // 这个提供STL标准的allocator接口  
  typedef simple_alloc<value_type, Alloc> data_allocator;  
  
  iterator start;               // 内存空间起始点  
  iterator finish;              // 当前使用的内存空间结束点  
  iterator end_of_storage;      // 实际分配内存空间的结束点  
}

 

// 获取几种迭代器  
  iterator begin() { return start; }  
  const_iterator begin() const { return start; }  
  iterator end() { return finish; }  
  const_iterator end() const { return finish; }  
  reverse_iterator rbegin() { return reverse_iterator(end()); }  
  const_reverse_iterator rbegin() const {  
    return const_reverse_iterator(end());  
  }  
  reverse_iterator rend() { return reverse_iterator(begin()); }  
  const_reverse_iterator rend() const {  
    return const_reverse_iterator(begin());  
  }  
  
  // 返回当前对象个数  
  size_type size() const { return size_type(end() - begin()); }  
  size_type max_size() const { return size_type(-1) / sizeof(T); }  
  // 返回重新分配内存前最多能存储的对象个数  
  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); }  
  const_reference operator[](size_type n) const { return *(begin() + n); }

构造函数示例 

// constructing vectors
#include <iostream>
#include <vector>
#include <assert.h>
#include <iterator> //istream_iterator,ostream_iterator,back_inserter 
//using namespace std;
int main ()
{  
    // 0. Create an empty vector v0  
    std::vector<int> v0;  
    assert(v0.empty());  
  
    // 1. Create a vector v1 with 3 elements of default value 0  
    std::vector<int> v1(3);  
  
    // 2. Create a vector v2 with 5 elements of value 2  
    std::vector<int> v2(5, 2);  
  
    // 3. Create a vector v3 with 3 elements of value 1 and with the allocator of vector v2  
    std::vector<int> v3(3, 1, v2.get_allocator());  
  
    // 4. Create a copy, vector v4, of vector v2  
    std::vector<int> v4(v2);  
  
    // 5. Create a vector v5 by copying the range v4[_First, _Last)  
    std::vector<int> v5(v4.begin() + 1, v4.begin() + 3);  
  
    std::cout << "v1 = ";  
    std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
  
    std::cout << "v2 = ";  
    std::copy(v2.begin(), v2.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
  
    std::cout << "v3 = ";  
    std::copy(v3.begin(), v3.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
  
    std::cout << "v4 = ";  
    std::copy(v4.begin(), v4.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
  
    std::cout << "v5 = ";  
    std::copy(v5.begin(), v5.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
  
    // 6. Move vector v2 to vector v6  
    std::vector<int> v6(std::move(v2));  
  
    std::cout << "v6 = ";  
    std::copy(v6.begin(), v6.end(), std::ostream_iterator<int>(std::cout, " "));  
    std::cout << std::endl;  
}
// constructing vectors
#include <iostream>
#include <vector>

int main ()
{
  // constructors used in the same order as described above:
  std::vector<int> first;                                // empty vector of ints
  std::vector<int> second (4,100);                       // four ints with value 100
  std::vector<int> third (second.begin(),second.end());  // iterating through second
  std::vector<int> fourth (third);                       // a copy of third

  // the iterator constructor can also be used to construct from arrays:
  int myints[] = {16,2,77,29};
  std::vector<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );
  myints[2] = 0;
  std::cout << "The contents of fifth are:";
  for (std::vector<int>::iterator it = fifth.begin(); it != fifth.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}
//输出:The contents of fifth are: 16 2 77 29

成员函数 

在容器内查看容器名称 查看容器大小_在容器内查看容器名称

注意

vector<char> v;    
v.resize(41);
strcpy(&v[0],"hello world!");
printf("%s\n",&v[0]);    //OK
printf("%s\n",v.begin()); //ERROR

    迭代器不应该作为第一个元素的地址传递。因为迭代器不一定直接由指针实现(此版本的vector的迭代器刚好直接由指针实现)

template <class T, class Alloc = alloc>  
class vector  
{  
  typedef T value_type;
  typedef value_type* iterator; 
}

 

 

deque

参考

  • http://www.cplusplus.com/reference/queue/queue/

 特点

    deque是一种优化了的、对序列两端元素进行添加和删除操作的基本序列容器。它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小。它不需要重新分配空间,所以向末端增加元素比vector 更有效。

    实际上,deque 是对vector 和list 优缺点的结合,它是处于两者之间的一种容器。

    (1) 随机访问方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;

    (2) 可以在内部进行插入和删除操作,但性能不及list ;

    (3) 可以在两端进行push 、pop ;

    (4) 相对于verctor 占用更多的内存。

    双向队列和向量很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样)。

    

在容器内查看容器名称 查看容器大小_成员函数_02

    

在容器内查看容器名称 查看容器大小_迭代器_03

     

    可以看出deque头部的插入和删除操作与尾部性能一致 ,但在中间的插入和删除操作性能不及list 。

deque和vector的不同之处

1、两端都能够快速插入和删除元素。vector只能在尾端进行。

2、deque的元素存取和迭代器操作会稍微慢一些。因为deque的内部结构会多一个间接过程。

3、迭代器是特殊的智能指针,而不是一般指针。它需要在不同的区块之间跳转。

4、deque可以包含更多的元素,其max_size可能更大。因为不止使用一块内存。

5、不支持对容量和内存重分配时机的控制。在除了首尾两端的其他地方插入和删除元素,都将会导致指向deque元素的任何pointers、references、iterators失效。不过,deque的内存重分配优于vector。因为其内部结构显示不需要复制所有元素。

6、deque的内存区块不再被使用时,会被释放。deque的内存大小是可缩减的。不过,是不是这么做以及怎么做由实作版本定义。

deque和vector相似的特性:

1、在中间部分插入和删除元素相对较慢,因为所有元素都要被移动。

2、迭代器属于随即存取迭代器。

最好采用deque的情形:

1、需要在两端插入和删除元素。

2、无需引用容器内的元素。

3、要求容器释放不再使用的元素。

注意:

1、除了at()函数,其他成员函数都不会检查索引或迭代器是否有效。

2、元素的插入和删除可能会导致内存重新分配。所以任何插入或删除操作都会使所有指向deque元素的pointers、reference、iterators失效。唯一例外的是在首尾插入元素之后,pointers和reference可能仍然有效,但是iterators失效。

#include <iostream>
#include <deque>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;

int main()
{
    // create empty deque of strings
    deque<string> coll;

    // insert several elements
    coll.assign (3, string("string")); //将3个"string"副本赋值给coll
    coll.push_back ("last string");
    coll.push_front ("first string");

    // print elements separated by newlines
    copy (coll.begin(), coll.end(),
          ostream_iterator<string>(cout,"\n"));
    cout << endl;

    // remove first and last element
    coll.pop_front();
    coll.pop_back();

    // insert ``another'' into every element but the first
    for (unsigned i=1; i<coll.size(); ++i) {
        coll[i] = "another " + coll[i];
    }

    // change size to four elements
    coll.resize (4, "resized string"); //将大小(元素的数目)改为4,如果大小增长,增加的元素都是"resized string"的副本

    // print elements separated by newlines
    copy (coll.begin(), coll.end(),
          ostream_iterator<string>(cout,"\n"));
}

在容器内查看容器名称 查看容器大小_成员函数_04

list

参考

  • http://www.cplusplus.com/reference/list/list/

    list使用双向链表管理元素。

在容器内查看容器名称 查看容器大小_迭代器_05

特点

list的内部结构和vector或deque截然不同,所以在几个主要方面与vector和deque存在明显区别:

1.list不支持随机存取,即如果你要存取第5个元素,你必须顺着串链一一爬过前4个元素,所以在list中随机遍历任意元素,是很缓慢的行为;

2.任何位置(不只是两端)执行元素的安插和删除都非常快,始终是常数时间内完成,因为无需移动任何其他元素,实际上内部只是进行了一些指针操作而已;

3.安插和删除动作并不会造成指向其他元素的各个pointers,references,iterators失效;

4.list对于异常有着:要么操作成功,要么什么都不发生。

5.list提供了不少特殊的成员函数,专门用于移动元素,较通用的STL算法,这些函数执行起来速度更快,因为无须拷贝和移动,只需调整若干指针即可;

6.list内部提供了很多高效快速的成员函数,用来移动list内部元素或者不同list之间的元素;

list所提供的成员函数反应出它和vector以及deque的不同:

1.      由于不支持随机存取,list既不提供下标操作符,也不提供at()

2.      list并未提供容量、空间重新分配等操作函数,因为没有必要。每个元素都有自己的内存。

3.      list提供不少特殊的成员函数,专门用于移动元素。

函数

 

#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>
using namespace std;

void printLists (const list<int>& l1, const list<int>& l2)
{
    cout << "list1: ";
    copy (l1.begin(), l1.end(), ostream_iterator<int>(cout," "));
    cout << endl << "list2: ";
    copy (l2.begin(), l2.end(), ostream_iterator<int>(cout," "));
    cout << endl << endl;
}

int main()
{
    // create two empty lists
    list<int> list1, list2;

    // fill both lists with elements
    for (int i=0; i<6; ++i) {
        list1.push_back(i);
        list2.push_front(i);
    }
    printLists(list1, list2);

    // insert all elements of list1 before the first element with value 3 of list2
    // - find() returns an iterator to the first element with value 3
    list2.splice(find(list2.begin(),list2.end(),  // destination position
                      3),
                 list1);                          // source list
    printLists(list1, list2);

    // move first element to the end
    list2.splice(list2.end(),        // destination position
                 list2,              // source list
                 list2.begin());     // source position
    printLists(list1, list2);

    // sort second list, assign to list1 and remove duplicates
    list2.sort();
    list1 = list2;
    list2.unique();
    printLists(list1, list2);

    // merge both sorted lists into the first list
    list1.merge(list2);
    printLists(list1, list2);
}

在容器内查看容器名称 查看容器大小_迭代器_06