一、简介
1) 默认构造函数,构造一个空的容器
顺序容器是拥有单一类型的一个有序集合,vector ,list(双向链表),queue(队列);
关联容器支持查询一个元素是否存在,也就是对元素进行排序的容器,map(映射),set(集合)。map 每个元素拥有两个数据,一个是索引,一个是值,而set只相当于一个排序后的集合。
二、vector
vector是一个顺序容器,相当于一个动态数组。因为vector中元素是连续存储的,所以除了迭代器也可以使用指针偏移来访问,也就是说vector的任意元素可以通过指针和偏移量传递给其他函数。
vector是自动申请或释放存储空间的。vector占用的空间通常比实际需要的更大,因为这样就不必每次修改时都重新申请空间。可以通过capacity()函数来查询总共占用的空间,额外的空间也可以通过shrink_to_fit()函数来释放
重新分配空间需要话费一些代价,如果事先知道元素数量的花可以使用reserve()函数来避免重新分配空间。
2.1 时间复杂度
- 随机访问 O(1)
- 在末尾删除或者插入元素 O(1)
- 擦除元素,插入元素 O(n),具体是插入位置和end()直接的距离
template< class T, |
- T 元素类型
- Allocator 用来申请空间存储元素,一般不用
vector<bool> 经过专门优化,以bit为单位,可以有效节省空间
2.4 迭代器失效
迭代器在什么情况下会失效呢,在我的理解,一是元素被释放,二是重新分配空间
操作 | 迭代器 |
所有读操作和swap函数 | 不会失效 |
reserve,shrink_to_fit,clear_,operator =等重新分配空间的情况 | 实效 |
erase擦除元素 | 被擦除的元素和其之后的元素都会失效,包括.end() |
push_back,emplace_back | 若重新分配,都失效,否则,只有end()失效 |
insert,emplace,resize | 若重新分配,都失效,否则,所有在其之后的节点,失效 |
pop_back | 被pop的元素和end()失效 |
2.5 成员变量
value_type | T |
allocator_type | Allocator |
size_type | size,无符号整数 |
difference_type | 有符号整数类型? |
reference | 引用 Allocator::const_reference |
const_reference | const引用 |
pointer | |
const_pointer | |
iterator | 迭代器 |
const_iterator | const迭代器 |
reverse_iterator | 反向迭代器 |
const_reverse_iterator | const~ |
2.6 成员函数
2.6.1 构造函数
explicit vector( const Allocator& alloc = Allocator() ); (1) | (until C++14) | |
vector() : vector( Allocator() ) {} explicit vector( const Allocator& alloc ); | (since C++14) | |
(2) | ||
explicit vector( size_type count, const T& value = T(), | (until C++11) | |
vector( size_type count, const T& value, | (since C++11) | |
(3) | ||
explicit vector( size_type count ); | (since C++11) (until C++14) | |
explicit vector( size_type count, const Allocator& alloc = Allocator() ); | (since C++14) | |
template< class InputIt > vector( InputIt first, InputIt last, | (4) | |
vector( const vector& other ); | (5) | |
vector( const vector& other, const Allocator& alloc ); | (5) | (since C++11) |
vector( vector&& other ) | (6) | (since C++11) |
vector( vector&& other, const Allocator& alloc ); | (6) | (since C++11) |
vector( std::initializer_list<T]]> init, const Allocator& alloc = Allocator() ); | (7) | (since C++11) |
2) 构造函数,提供元素数量和初始值
3)值提供元素数量
4)提供一个范围,比如另一个容器的begin(),end();
5) 拷贝构造函数,提供另一个容器
6)移动构造函数,提供另一个容器.移动构造函数的参数是“右值引用&&”,是临时变量,占用临时变量的空间来提高性能,
http://www.cnblogs.com/hujian/archive/2012/02/13/2348621.html
7)用一些元素来初始化容器
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
void printV(vector<int> &num){
vector<int>::iterator it;
for(it=num.begin();it!=num.end();it++){
cout<<*it<<" ";
}
cout<<endl;
}
int main(){
//constructor
vector<int> num1;
cout<<"num1: ";
printV(num1);
vector<int> num2(5,9);
cout<<"num2: ";
printV(num2);
vector<int> num3(4);
cout<<"num3: ";
printV(num3);
vector<int> num4(num1.begin(),num1.end());
cout<<"num4: ";
printV(num4);
// vector<int> num7={1,2,3,4,5,6,7,8,9};c++11中支持
// cout<<"num7: ";
// printV(num7);
vector<int> num5(num2);
cout<<"num5: ";
printV(num5);
cout<<"num2 after copy constructor: ";
printV(num2);
vector<int> num6(num2);
cout<<"num6: ";
printV(num6);
cout<<"num2 after move constructor: ";
printV(num2);
int x[5]={1,2,3,4,5};
vector<int> num8(x,x+5);
cout<<"num8 range constructor4 by array: ";
printV(num8);
}
|
2.6.2 赋值操作 operator =
vector& operator=( const vector& other ); | (1) | |
vector& operator=( vector&& other ); | (2) | (since C++11) |
vector& operator=( std::initializer_list<T]]> ilist ); | (3) | (since C++11) |
三种,分别是拷贝赋值函数,移动赋值函数,初始化列表赋值,与构造函数基本相同。
2.6.3 获取分配器类型 //?
get_allocator
2.6.4 访问元素
- at:返回一个引用,若pos超过size(),会返回一个一异常
- operator[] :返回一个引用,但是不会检查是否越界
- front:返回第一个元素的引用,但是对于空容器结果是不确定的
- back:返回最后一个元素的引用,对于空容器结果也是不确定的
- data:c++11,对于非空容器,返回的是&front()//?
- begin/cbegin
- end/cend
- rbegin/crbegin
- rend/crend
2.6.6 容量Capacity
- empty:检查是否为空
- size:返回元素的数目
- max_size:最大可能的元素数目,通常为很大很大的数,是容器能够达到的极限
- reverse:参数为新容量,返回值为void
- capacity:已分配最大空间数目(单位是元素)
- shrink_to_fit:重新分配空间,使空间刚刚合适
2.6.7 修改元素
- clear:清空容器,无返回值
- insert:添加元素,返回新添加第一个元素的迭代器
- 参数为迭代器,值,在该迭代器之前插入一个值
- 参数为迭代器,count,value,在该迭代器之前添加多个值
- 参数为迭代器,first,last,在该迭代器之前,添加[first,last)的值
- 参数迭代器,初始化列表(initializer_list<T> ilist, 在该迭代期之前添加ilist(C11)
- emplace:与insert有所区别,暂不解释//?
- erase:擦除元素,返回被擦除最后一个元素的下一个迭代器
- 参数为迭代器,删除该迭代器指向的元素
- 参数为迭代器first,迭代器last,删除[first,last)的内容,前闭后开
- push_back 返回值为void
-
- 在容器的最后添加元素,也分拷贝和移动两种,参考构造函数
- emplace_back 暂不解释
- pop_back() 返回值为void
- resize 调整元素的数量,返回值为 void
-
- 参数为count
- 参数为count,value
- 若count小于当前size,则相当于做size-count次pop操作
- 若count大于当前size,则多出来的用value补齐
- 参数为count
- swap:参数为容器引用,交换两个容器的值,迭代器都还有效
2.7 非成员函数
分别按索引比较,比如lhs[i]<rhs[i],for all i,则lhs<rhs;编译时发现除了==,!=,只要第一个元素符合,就会符合,不知道到底是怎样,先放在这里。//?
- == 如果两个容器的所有元素都相等,返回true,size也必须相同
- != 与==相反
- < 如果等式左边的元素们按字典顺序小于右边等式的元素们,返回true
- <=
- >
- >=
- swap 交换两个容器的元素,size不必相等
三、疑问
- emplace系列函数
- 移动构造,移动赋值,右值引用
- <=,<,>=,>
- 和数组差不多,假设删除一个元素后将后面的元素顺序前移动,为什么被erase的iterator失效
#include <iostream>
#include <vector>
#include <iterator>
using namespace std;
//iterator
void printV(vector<int> &num){
vector<int>::iterator it;
for(it=num.begin();it!=num.end();it++){
cout<<*it<<" ";
}
cout<<endl;
}
//reverse_iterator
void r_printV(vector<int> &num){
vector<int>::reverse_iterator it;
for(it=num.rbegin();it!=num.rend();it++){
cout<<*it<<" ";
}
cout<<endl;
}
int main(){
//constructor
vector<int> num1;
cout<<"num1: ";
printV(num1);
vector<int> num2(5,9);
cout<<"num2: ";
printV(num2);
vector<int> num3(4);
cout<<"num3: ";
printV(num3);
vector<int> num4(num1.begin(),num1.end());
cout<<"num4: ";
printV(num4);
// vector<int> num7={1,2,3,4,5,6,7,8,9};c++11中支持
// cout<<"num7: ";
// printV(num7);
vector<int> num5(num2);
cout<<"num5: ";
printV(num5);
cout<<"num2 after copy constructor: ";
printV(num2);
vector<int> num6(num2);
cout<<"num6: ";
printV(num6);
cout<<"num2 after move constructor: ";
printV(num2);
int x[5]={1,2,3,4,5};
vector<int> num8(x,x+5);
cout<<"num8 range constructor4 by array: ";
printV(num8);
//element access
int& xByAt=num8.at(3);
xByAt=13;
printV(num8);
//cout<<"exception "<<endl;
//cout<<num8.at(10)<<endl;
//capacity
cout<<"size:"<<num8.size()<<endl;
cout<<"max_size:"<<num8.max_size()<<endl;
cout<<"capacity:"<<num8.capacity()<<endl;
vector<int>::iterator it;
int x1[3]={33,33,33};
it=num8.begin();
//insert
it=num8.insert(it,11);
it=num8.insert(it,2,22);
it=num8.insert(it,x1,x1+3);
cout<<"num8 after insert: ";
printV(num8);
//non-member function
int y[5]={1,9,3,5};
int z[4]={2,9,3,5};
vector<int> num9(y,y+4);
vector<int> num10(z,z+4);
cout<<"<:"<<(num9<num10)<<endl;
//swap
cout<<"num9: ";
printV(num9);
cout<<"num10: ";
printV(num10);
cout<<"after swap:"<<endl;
swap(num9,num10);
cout<<"num9: ";
printV(num9);
cout<<"num10: ";
printV(num10);
// cout<<"before erase, begin():"<<int(num9.begin())<<endl;
// num9.erase(num9.begin());
// cout<<num9.capacity()<<endl;
// cout<<"after erase, begin():"<<int(num9.begin())<<endl;
}