顺序容器C++
Posted 扣得君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了顺序容器C++相关的知识,希望对你有一定的参考价值。
第9章 顺序容器
顺序容器为开发者提供了控制元素存储和访问顺序的能力,顺序不依赖元素的值,而是元素加入元素容器时的位置相对应
顺序容器概述
如list、forward_list是链式存储结构,而vector、deque、array、string为顺序存储结构,在增删改等操作上它们会有不同的特性
构造函数
容器是C++对数据结构的一种封装,器本质是面向对象的设计,掌握相关的构造是一件理所当然的事情
默认构造
默认构造相关的空容器
//example1.cpp
list<int> m_list;//默认构造函数构造空容器
vector<int> m_vector;
拷贝构造
将m_vector拷贝一份到m_vector_copy
//example1.cpp
vector<int> m_vector_copy(m_vector);
迭代器范围构造
其范围是[begin,end)范围内的元素
//example1.cpp
vector<int> m_vector_1(m_vector_copy.begin(), m_vector_copy.end());
列表初始化构造
//example1.cpp
list<int> m_list_11, 2, 3;
for(auto&item:m_list_1)
cout << item << endl;//1 2 3
迭代器
迭代器的范围是[begin,end),当容器为空时begin等于end
//example2.cpp
list<int> m_list1, 2, 3;
list<int>::iterator iter = m_list.begin();
while(iter!=m_list.end())
cout << *iter << endl;//1 2 3
iter++;
容器类型成员
每个容器都定义了多个类型,如size_type、iterator、const_iterator
size_type
//example3.cpp
list<int> m_list1, 2, 3;
list<int>::size_type size = m_list.size();
cout << size << endl;//3
iterator
//example3.cpp
list<int>::iterator iter = m_list.begin();
const_iterator
//example3.cpp
list<int>::const_iterator const_iter = m_list.begin();
//*const_iter = 1;//error readonly
reference
元素引用类型
//example3.cpp
list<int>::reference m_list_reference=*(m_list.begin()); // int &m_list_reference;
m_list_reference = 999;
cout << *(m_list.begin()) << endl;//999
const_reference
const引用
//example3.cpp
list<int>::const_reference m_const_list_reference = *(m_list.begin());//const int &m_const_list_reference
//m_const_list_reference = 888;
//error:: readonly
for(vector<int>::const_reference item:m_list)//迭代器for循环
cout << item << endl;//1 2 3
value_type
容器存储类型的值类型
//example3.cpp
list<int>::value_type num = 9;//int num
pointer
容器存储类型的指针类型
//example3.cpp
list<int>::pointer ptr;//int *ptr
const_pointer
容器存储类型const指针类型
//example3.cpp
list<int>::const_pointer const_ptr;//const int *const_ptr
difference_type
迭代器之间的距离
//example3.cpp
vector<int> vec = 1, 2, 3;
vector<int>::difference_type distance=end(vec) - begin(vec);
cout << distance << endl;//3
begin和end成员
我们以前接触到的begin和end,分别指向第一个元素与最后一个元素的下一个位置,begin和end有多个版本
r开头的返回反向迭代器,c开头的返回const迭代器
reverse_iterator与rend与rbegin
//example4.cpp
vector<int> vec = 1, 2, 3, 4;
vector<int>::reverse_iterator iter = vec.rbegin();
while(iter!=vec.rend())
cout << *iter << endl;//4 3 2 1
iter++;
cbegin和cend
//example4.cpp
vector<int>::const_iterator const_iter = vec.cbegin();
//*const_iter = 999;
crbegin和crend
甚至还有这样的组合,真实离了个大谱了
//example4.cpp
vector<int>::const_reverse_iterator const_reverse_iter = vec.crbegin();
while (const_reverse_iter!=vec.crend())
cout << *const_reverse_iter << endl;//4 3 2 1
const_reverse_iter++;
容器定义和初始化
主要要掌握容器的构造函数的相关重载,以及赋值拷贝等特性
在前面的构造函数内容中我们已经过实践,可以进行复习与在此学习
存储不同类型元素的容器的转换
是没有这样的转换的,如将vector<int>转换为vector<float>,C++中并没有相关的直接操作,但是允许我们使用迭代器范围方式初始化,迭代器相关元素类型必须有相关的构造函数
//example5.cpp
#include<iostream>
#include<vector>
using namespace std;
int main(int argc,char**argv)
vector<int> vec11, 2, 3;
//vector<float> vec2(vec1);//没有相关构造函数
vector<float> vec2(vec1.begin(), vec1.end());//可以用迭代器进行初始化
int num=float(*vec1.begin());//背后可以使用元素类型的构造函数
cout << num << endl;//1
//string与char*
const char *str1 = "hello";
const char *str2 = "world";
vector<const char *> str_vec = str1, str2;
vector<string> string_vec(str_vec.begin(),str_vec.end());//可以用迭代器进行初始化
string str(*str_vec.begin());//背后可以使用元素类型的构造函数
cout << str << endl;//hello
return 0;
标准库array
array具有固定大小
除了C风格的数组之外,C++提供了array类型,其也是一种顺序容器
//example6.cpp
#include<iostream>
#include<array>
using namespace std;
int main(int argc,char**argv)
//一维array
array<int, 10> m_array;
m_array[0] = 1;
cout << m_array[0] << endl;
//二维array
array<array<int, 10>, 10> matrix;
matrix[0][0] = 1;
cout << matrix[0][0] << endl;//1
//同理可以具有容器的特性
array<array<int, 10>, 10>::size_type size=matrix.size();//size_type
array<array<int, 10>, 10> copy = matrix;//拷贝构造
array<array<int, 10>, 10>::iterator iter = matrix.begin();//迭代器等
cout << (*iter)[0] << endl;//1
return 0;
赋值与swap
//example7.cpp
vector<int> vec1 = 1, 2, 3;
vector<int> vec2 = 3, 2, 1;
//c1=c2
vec2 = vec1;//拷贝
print_vec(vec1,"vec1");//vec1:1 2 3
print_vec(vec2, "vec2");//vec2:1 2 3
//c=a,b,c...通过列表赋值
vec1 = 4, 5, 6,7;
print_vec(vec1, "vec1");//vec1:4 5 6 7
//swap(c1,c2) 交换两容器的内容
swap(vec1,vec2);
print_vec(vec1,"vec1");//vec1:1 2 3
print_vec(vec2, "vec2");//vec2:4 5 6 7
//assign操作不适用于关联容器和array
vec1.assign(8,9,10);//列表assign
vec1.assign(vec2.begin(), vec2.end());//迭代器assign
vec1.assign(10, 999);//赋值为10个999
容器大小操作
容器具有成员函数size,其返回类型为相应容器的size_type,以及empty成员函数
//example8.cpp
vector<int> vec1 1, 2, 3;
string str1 = "123";
vector<int>::size_type vec1_size = vec1.size();
string::size_type str1_size = str1.size();
cout << "vec1_size " << vec1_size << endl;//vec1_size 3
cout << "str1_size " << str1_size << endl;//str1_size 3
cout << str1.empty() << endl;//0
cout << vec1.empty() << endl;//0
容器与关系运算符
容器之间也可以使用<、>、==关系运算符进行比较运算
运算规则与string的关系运算类似
1、如果两个容器具有相同大小且所有元素都两两对应相等,则者两个容器相等,否则两个容器不等
2、如果两个容器大小不同,但较小容器中每个元素都等于较大容器中的对应元素,则较小容器小于较大容器
3、如果两个容器都不是另一个容器的前缀子序列,则它们的比较结果取决于第一个不相等的元素的比较结果
//example9.cpp
int arr1[10]1, 2, 3, 4, 5;
int arr2[10]1, 2, 3, 4, 5;
cout << (arr1 == arr2) << endl;//0
//为什么 本质上比较的是头地址哦,忘了的话要去复习数组章节了
//==
array<int, 5>array11, 2, 3, 4, 5;
array<int, 5>array21, 2, 3, 4, 5;
cout << (array1 == array2) << endl;//1
vector<int> vec1 = 1, 1, 2, 3;
vector<int> vec2 =
1,
1,
3,
1
;
cout << (vec1 == vec2) << endl;//0
cout << (vec1 <= vec2) << endl;//1
cout << (vec1 > vec2) << endl;//0
容器的关系运算符依赖于元素的关系运算符,只有容器的元素支持关系运算时,容器整体才可以进行关系运算
顺序容器操作
主要包括增删改查等操作
向顺序容器添加元素
向容器内添加元素的有多种方式,不同的容器也有相应的约束以及仅有的特性
push_back
在尾部创建一个值为t的元素返回void,除了array和forward_list之外,每个顺序容器都支持push_back
//example10.cpp
list<int> m_list = 1, 2, 3;
vector<int> m_vector = 1, 2, 3;
m_list.push_back(4);
m_list.push_back(4);
//forward_list不支持push_back
push_front
在前面添加元素
//example12.cpp
//list forward_list deque容器支持push_front
list<int> m_list = 1, 2, 3;
m_list.push_front(0);
for(auto&item:m_list)
cout << item << endl;//0 1 2 3
insert
在指定位置添加新的元素,vector、deque、list、string都支持insert,forward_list提供了特殊版本的insert
- 在容器中的特定位置添加元素
//example14.cpp
list<int> m_list = 1, 2, 3;
m_list.insert(m_list.begin(), 0);//添加到begin()的前面
m_list.insert(m_list.end(), 4);//添加到end前面
for(auto&item:m_list)
cout << item << endl;//0 1 2 3 4
- 插入范围内元素
//example14.cpp
//插入范围内元素
vector<int> vec1 = 1, 2, 3;
vector<int> vec2 = ;
//insert(iter,num,element)
vec2.insert(vec2.begin(), 3, 0);
for(auto&item:vec2)
cout << item << endl;//0 0 0
//迭代器范围
vec2.insert(vec2.begin(),vec1.begin(),vec1.end());
for(auto&item:vec2)
cout << item << endl;//1 2 3 0 0 0
//列表insert
auto iter=vec2.insert(vec2.begin(), 777, 888, 999);
for(auto&item:vec2)
cout << item << endl;//777 888 999 1 2 3 0 0 0
//新标准中insert返回插入元素中的第一个元素的迭代器
cout << *iter << endl;//777
emplace
emplace主要有三种,emplace、emplace_back、emplace_front分别对应insert、push_back、push_front,二者的区别是后者直接拷贝到容器内,前者则是将参数传递给元素类型的构造函数
//example15.cpp
class Person
public:
int age;
string name;
Person() = default;
Person(int age,string name):age(age),name(name)
;
//emplace 与 insert 异曲同工
m_list.emplace(m_list.begin(), 19, "she");
emplace_front
//example13.cpp
m_list.emplace_front(19,"she");
m_list.emplace_front();//使用默认构造函数
emplace_back
//example11.cpp
list<Person> m_list;
//创建临时变量 push_back其拷贝后的副本
m_list.push_back(Person(19,"gaowanlu"));
m_list.emplace_back(19,"she");//传递元素构造参数
访问元素
at(n)
适用于string、vector、deque、array ,下标访问越界时将会抛出out_of_range异常
//example16.cpp
string str = "hello";
char &ch = str.at(0);
ch = 'p';
cout << str << endl;//pello
back()
back不适用于forward_list ,当容器为空时,函数行为没有定义将会卡住
vector<int> vec1 = 1, 2, 3, 4;
int &last_el = vec1.back();//最后一个元素的引用
front()
返回第一个元素的引用 ,当容器为空时,函数行为没有定义将会卡住
int &first = vec1.front();
c[n]
当容器为空时,函数行为没有定义将会卡住
int &num = vec1[0];
num = 999;
cout << vec1[0] << endl;//999
删除元素
删除元素会改变容器的大小,标准库提供的删除操作不支持array
pop_front和pop_back
pop_front()为删除首元素,pop_back为删除尾元素,vector与string不支持push_front与pop_front,forward_list不支持pop_back,同时不能对一
以上是关于顺序容器C++的主要内容,如果未能解决你的问题,请参考以下文章