简介
STL提供有两种容器库,分别为序列式容器和关联式容器,
序列式容器:array<T,N>,vector< T >,deque< T >,list< T>,forward_list< T >
使用方法
一、创建容器
- array< T,N > 数组容器
std::array<int,5> values; //5个随机值
std::array<int,5> values{}; //5个0
std::array<int,5> values{1,2}; //存有1、2和3个0
- vector< T > 向量容器
std::vector<int> values; //未分配内存空间
std::vector<int> values(5); //创建时有5个为0的元素
std::vector<int> values(5,1); //创建时有5个为1的元素
std::vector<int> values1{3,1}; //有2个元素3和1
std::vector<int> values2(values1); //和values1一样的容器
std::vector<int> values2(std::begin(values1),std::end(values1)); //和 values1一样的容器
- deque< T > 双端队列容器
std::deque<int> values; //未分配内存空间
std::deque<int> values(5); //创建时有5个为0的元素
std::deque<int> values(5,1); //创建时有5个为1的元素1
std::deque<int> values2(values); //和 values一样的容器
std::deque<int> values2(std::begin(values),std::end(values)); //和 values一样的容器
- list< T > 双向链表容器
std::list<int> values; //未分配内存空间
std::list<int> values(5); //创建时有5个为0的元素
std::list<int> values(5,1); //创建时有5个为1的元素1
std::list<int> values2(values); //和values一样的容器
std::list<int> values2(std::begin(values),std::end(values)); //和 values一样的容器
- forward_list< T > 单向链表容器
其和双向链表创建方式相同
二、添加、插入、删除元素
- array< T,N > 数组容器
在创建容器时进行初始化赋值元素,同时可通过访问元素进行修改元素值
- vector< T > 向量容器
std::vector<int> values;
//尾部添加
values.push_back(1); //{1}
values.emplace_back(1); //emplace_back效率较高, C++ 11 标准中新增的方法
//指定位置之前插入
values.insert(values.begin() , 3); //{3,1}
std::array<int,3> test{ 4,5,6 };
values.insert(values.end(), test.begin(), test.end());//{3,1,4,5,6}
values.insert(values.begin()+1,{7,8}); //{3,7,8,1,4,5,6}
values.emplace(values.begin(), 9); //{9,3,7,8,1,4,5,6},每次只能插入一个元素 ,效率比insert高
//删除元素
values.pop_back();//{9,3,7,8,1,4,5},删除尾部元素
auto iter = values.erase(values.begin() + 1);{9,7,8,1,4,5},删除指定位置元素,iter指向被删位置的下一个元素
auto iter = values.erase(values.begin() + 1,values.begin() -2);{9,4,5},删除指定区域元素,iter指向被删区域的下一个元素
auto iter1 = std::remove(values.begin(), values.end(), 9);//{4,5,5},只是把相同元素给覆盖了,容器大小和容量没有改变 ,iter1 指向最后一个覆盖元素的下一个元素 即第二个5的位置
values.erase(iter1 ,values.end() );//{4,5}
values.clear();//清空容器
- deque< T > 双端队列容器
std::deque<int> values;
//添加
values.push_back(1); //{1} //尾部添加
values.emplace_back(2); //{1,2},emplace_back效率较高, C++ 11 标准中新增的方法
values.push_front(3); //{3,1,2} //头部添加
values.emplace_front(2); //{2,3,1,2},emplace_front效率较高, C++ 11 标准中新增的方法
//指定位置之前插入
values.insert(values.begin() , 3); //{3,1}
std::array<int,3> test{ 4,5,6 };
values.insert(values.end(), test.begin(), test.end());//{3,1,4,5,6}
values.insert(values.begin()+1,{7,8}); //{3,7,8,1,4,5,6}
values.emplace(values.begin(), 9); //{9,3,7,8,1,4,5,6},每次只能插入一个元素 ,效率比insert高
//删除元素
values.pop_back();//{9,3,7,8,1,4,5},删除尾部元素
values.pop_front();//{3,7,8,1,4,5},删除头部元素
auto iter = values.erase(values.begin() + 1);{7,8,1,4,5},删除指定位置元素,iter指向被删位置的下一个元素
auto iter = values.erase(values.begin() + 1,values.begin() -2);{7,4,5},删除指定区域元素,iter指向被删区域的下一个元素
values.clear();//清空容器
- list< T > 双向链表容器
std::list<int> values;
//添加
values.push_back(1); //{1} //尾部添加
values.emplace_back(2); //{1,2},emplace_back效率较高, C++ 11 标准中新增的方法
values.push_front(3); //{3,1,2} //头部添加
values.emplace_front(2); //{2,3,1,2},emplace_front效率较高, C++ 11 标准中新增的方法
//指定位置之前插入
values.insert(values.begin() , 3); //{3,1}
std::array<int,3> test{ 4,5,6 };
values.insert(values.end(), test.begin(), test.end());//{3,1,4,5,6}
values.insert(values.begin()+1,{7,8}); //{3,7,8,1,4,5,6}
values.emplace(values.begin(), 9); //{9,3,7,8,1,4,5,6},每次只能插入一个元素 ,效率比insert高
list<int> list1{ 1,2,3,4 }, list2{5,6,7}, auto it = list1.begin()+1;
list1.splice(it , list2); // list1: {1,5,6,7,2,3,4} list2:{} it还是指向2
list2.splice(list2.begin(), list1,it);// list1: {1,5,6,7,3,4} list2:{2} it还是指向2
list2.splice(list2.begin(), list1, list1.begin(), list1.end());// list1: {} list2:{1,5,6,7,3,4,2}
//删除元素
values.pop_back();//{9,3,7,8,1,4,5},删除尾部元素
values.pop_front();//{3,7,8,1,4,5},删除头部元素
auto iter = values.erase(values.begin() + 1);{7,8,1,4,5},删除指定位置元素,iter指向被删位置的下一个元素
auto iter = values.erase(values.begin() + 1,values.begin() -2);{7,4,5},删除指定区域元素,iter指向被删区域的下一个元素
values.remove(7);//{4,5}
values.clear();//清空容器
values.unique(); //删除容器中相邻的重复元素,只保留一份。
values.remove_if(); //删除容器中满足条件的元素。
- forward_list< T > 单向链表容器
std::forward_list<int> values;
//添加
values.push_front(4);//{4}, 头部添加
values.emplace_front(5);//{5,4}, 头部添加
//插入
values.insert_after(values.before_begin(), 6); //{6,5,4}
values.emplace_after(values.before_begin(), 6); //{6,6,5,4}
//删除
values.pop_front();{6,5,4},删除头部元素
values.erase_after();//删除容器中某个指定位置或区域内的所有元素
values.clear();//清空容器
三、容器元素个数
除了单向链表容器forward_list< T >未提供size()方法,其他容器都可调用values.size()得到元素个数
forward_list< T > values可用distance(values.begin(),values.end())得到
同时判断容器是否为空时,直接调用empty()效率较高。
四、容器元素访问及迭代器使用
迭代器可分为随机访问迭代器,双向访问迭代器,前向访问迭代器。
随机访问迭代器,双向访问迭代器都支持正向和反向迭代器的定义,而前向访问迭代器只支持正向迭代器的定义
- array< T,N > 数组容器
std::array<int,3> values{1,2,3};
//支持随机访问迭代器
values[0]; // 访问下标 0:1 1:2 2:3
values.at(0) // 相比[i] 更安全 防止越界访问
values.data() // 返回一个指向容器首个元素的指针 ,对指针移动可进行元素访问
auto iter = values.begin() //返回一个指向容器首个元素正向迭代器 ,对迭代器++可后移动可进行元素访问
auto iter = values.rbegin() //返回一个指向容器最后个元素反向迭代器 ,对迭代器++可前移动可进行元素访问
- vector< T > 向量容器
std::vector<int> values1{3,1};
//支持随机访问迭代器
values[0]; // 访问下标
values.at(0) // 相比[i] 更安全 防止越界访问
values.data() // 返回一个指向容器首个元素的指针 ,对指针移动可进行元素访问
auto iter = values.begin() //返回一个指向容器首个元素正向迭代器 ,对迭代器++可后移动可进行元素访问
auto iter = values.rbegin() //返回一个指向容器最后个元素反向迭代器 ,对迭代器++可前移动可进行元素访问
注意 :使用迭代器访问前提是容器已有元素,已分配了内存,再给容器调用reserve(n)重新申请容量或者添加元素之后,都可能会让容器重新分配到一片新的内存,所以迭代器需要重新生成。
- deque< T > 双端队列容器
std::vector<int> values1{3,1};
//支持随机访问迭代器
values[0]; // 访问下标
values.at(0) // 相比[i] 更安全 防止越界访问
auto iter = values.begin() //返回一个指向容器首个元素正向迭代器 ,对迭代器++可后移动可进行元素访问
auto iter = values.rbegin() //返回一个指向容器最后个元素反向迭代器 ,对迭代器++可前移动可进行元素访问
可以看到,前面三种容器都支持随机访问迭代器,也就支持[],at()的方式,但是deque()不支持data()方式访问,因为它的内存空间不一定是连续的,同时它们都支持正向和逆向的访问。
- list< T > 双向链表容器
std::list<int> values(5,1); //创建时有5个为1的元素1
//支持双向访问迭代器
auto iter = values.begin() //返回一个指向容器首个元素正向迭代器 ,对迭代器++可后移动可进行元素访问
auto iter = values.rbegin() //返回一个指向容器最后个元素反向迭代器 ,对迭代器++可前移动可进行元素访问
双向仅仅支持采用迭代器的方式访问元素,不支持[],at()方式,同时对迭代器的操作只支持ite++,或者–,==,!=操作符号
添加元素时迭代器不会失效,注意在删除元素时,指向被删除的元素的迭代器会失效,不能再对其进行操作
- forward_list< T > 单向链表容器
std::list<int> values(5,1); //创建时有5个为1的元素1
//支持前向访问迭代器
auto iter = values.begin() //返回一个指向容器首个元素正向迭代器 ,对迭代器++可后移动可进行元素访问
advance(iter , 2); //向前移动两个元素
只支持正向迭代器的定义。
五、总结
上面介绍了五种容器提供的常用方法以支持常用的操作,
元素在容器中的位置同元素的值无关,即容器不是排序的。将元素插入容器时,指定在什么位置,元素就会位于什么位置。
主要是迭代器的使用过程对容器进行添加元素或者删除元素需要多加注意。
上述使用auto定义迭代器,自动识别迭代器类型正向还是方向,实际正向迭代器类型:容器类名::iterator ; 反向迭代器类型:容器类名::reverse_iterator 。
后续介绍关联式容器的使用方法