目录
一、vector的初始化(9种)
二、vector的访问和遍历
2.1 访问(3种)
(1)使用下标运算符[]访问和修改
(2)使用迭代器访问
(3)使用at()函数访问
(4)data 访问
2.2 遍历(3种)
(1)下标遍历
(2)迭代器遍历
(3)元素(对象/for each)遍历
三、vector的函数:增删查改
3.1 查:获得字符串的信息
1. 容量
2.查找和操作首、尾元素的值 v.front;v.back()
3. 🧡查找某个字符所在位置 s.find()
3.2 增加
1. 🧡插入 v.insert()
2. 附加 v.push_back()
3.emplace()&emplace_back()
3.3 删除
1. 删除全部 v.clear()
2. 🧡删除最后一个元素 v.pop_back()
3. 🧡删除部分 v.erase()
4. 删除部分 v.remove() (未写完)
3.4 修改(未写完)
1.改:替换:v.replace()
2.改:排序 v.sort(v.begin().v.end())从小到大
3.改:反转 v.reverse(v.begin(),v.end())
3.5 对多个vector的操作
4.1 交换两个vector v1.swap(other vector)
二维数组
1. 二维数组初始化
2. 访问,遍历和修改
一、vector的初始化(9种)
除《C++ Primer》上提到的7种构造方式:
vector的初始化可以分为构造函数式初始化、集合式初始化和复制截取式初始化,这样方便理解和记忆哟(^U^)ノ
//空vctor的初始化
vector<int> v1;
//小括号构造函数式初始化
vector<int> v2(10, 0);
vector<int> v3(10);
//花括号集合枚举式初始化
vector<int> v4 = {1,2,3,4,5};
vector<string> v5{ "hi","can","I","help","you"};
//复制式初始化
vector<int> v6(v4);
vector<int> v7=v4;
除《C++ Primer》上提到的7种构造方式之外,还有两种复制截取其他vector来初始化的方法:
vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+7); //从数组中获得初值
二、vector的访问和遍历
2.1 访问(3种)
(1)使用下标运算符[]访问和修改
vector<int> v(10,0);
v[2];
返回对指定位置的元素的引用 pos。不执行边界检查。表明我们可以像使用数组一样使用 vector。
(2)使用迭代器访问
迭代器类型:
begin() 返回一个迭代器(iterator),指向vector地第一个元素
end() 返回一个迭代器,指向vector的最后一个元素的后一个位置
rbegin() 返回一个迭代器,即先reverse再使用迭代器,自然是指向最后一个元素了
rend() 返回一个迭代器, 指向第一个元素的前一个位置
v.begin()//指向第一个元素
v.end()//指向最后一个元素的下一个位置
v.rbegin()//指向最后一个元素
v.rend()//指向第一个元素的前一个位置
(3)使用at()函数访问
at 通过边界检查访问指定的元素,返回对指定位置的元素的引用 pos,并进行边界检查。如果 pos 不在容器范围内,则会引发类型为 std::out_of_range 的异常。
reference at( size_type pos );
const_reference at( size_type pos ) const;
(4)data 访问
data 用于直接访问基础数组
constexpr T* data() noexcept; (since C++20)
constexpr const T* data() const noexcept; (since C++20)
返回值:指向基础元素存储的指针。对于非空容器,返回的指针等于第一个元素的地址。如果 size() 为 0,则 data() 可能会或可能不会返回空指针。
2.2 遍历(3种)
(1)下标遍历
顺序遍历,下标递增
for(int i=0;i<v.size();i++){
cout<<v[i]<<' ';
}
逆序遍历,下标递减
for(int i=v.size()-1;i>=0;i--){
cout<<v[i];
}
(2)迭代器遍历
顺序遍历,使用正向迭代器
vector<string> v6 = { "hi","my","name","is","lee" };
for (vector<string>::iterator iter = v6.begin(); iter != v6.end(); iter++)
{
cout << *iter << endl;
//下面两种方法都都可以检查迭代器是否为空
cout << (*iter).empty() << endl;
cout << iter->empty() << endl;
}
逆序遍历,使用反向迭代器
for (vector<string>::reverse_iterator iter = v6.rbegin(); iter != v6.rend(); iter++)
{
cout << *iter << endl;
}
(3)元素(对象/for each)遍历
复制拷贝原vector的值,修改对象,原vector不改变
for(auto c:v){
cout<<c<<' ';
}
vector<int> demo(10);
int i = 0;
for (int i = 0; i < 10; ++i) {
demo[i] = i+10;
}
for (auto c : demo) {
c = i;
i++;
cout << c<<" ";
}
//虽然没报错,但是c=i是不成立的,c是拷贝复制了demo,
//不能修改原demo的值
cout << endl;
demo.erase(demo.begin() + 1, demo.begin() + 3);
for (auto c : demo) {
cout << c<<" ";
}
cout << endl;
输出:
0 1 2 3 4 5 6 7 8 9
10 13 14 15 16 17 18 19
三、vector的函数:增删查改
3.1 查:获得字符串的信息
1. 容量
容器大小 v.size()
v.size() 获取并返回容器中元素的个数
vector<int> v(10,0);
int size=v.size();
修改容器大小 v.resize()
void resize( size_type count ); (1)
void resize( size_type count, const value_type& value ); (2)
调整容器的大小以包含 count 元素。如果当前大小大于 count,则容器将缩小为其第一个 count 元素。如果当前大小小于 count,需要附加额外的拷贝值 value。在将大小调整为更小时,vector 容量不会减少,因为这将使所有迭代器失效,而是等效于调用 pop_back() 导致迭代器失效的情况。
容器是否为空 v.empty()
检查容器有没有元素,即是否 begin () == end ()。
vecot<int> v(10,0);
if(v.empty()!=v.end()){
cout<<"not empty";
}
v.clear();
if(v.empty()==v.end()){
cout<<"empty";
}
v.max_size()
返回由于系统或库实现限制,容器可以容纳的最大元素数。
size_type max_size() const noexcept;
v.reserve()
将 vector 的容量增加到大于或等于的值 new_cap。
void reserve( size_type new_cap );
分配给字符串的内存大小 v.capacity()
size_type capacity() const noexcept;
删除未用的容量 shrink_to_fit()
void shrink_to_fit(); (since C++11)
2.查找和操作首、尾元素的值 v.front;v.back()
v.front();//返回首个元素
v.front()++;//对首个元素操作
v.back();//返回最后一个元素
v.back()=10;//对最后一个元素操作
返回对容器中第一个/最后一个元素的引用,空容器调用 back 会导致未定义的行为。
3. 🧡查找某个字符所在位置 s.find()
3.2 增加
1. 🧡插入 v.insert()
insert()函数是向vector插入元素,既然是插入,当然要知道【插哪里、插什么、插多少】三要素啦!记住这三要素,insert的语法就很好掌握啦!
PS:不同于string既可以用迭代器也可以用下标,vector的插入看起来只用迭代器来表示被插位置呢,更简单了呢!
1.插入一个元素! 在迭代器pos指向的位置的前一个位置插入一个新的元素elem,并返回元素位置的迭代器。 | iterator insert(pos,elem) |
2.插入多个相同元素! 在迭代器pos指向的位置的前一个位置插入n个新的元素elem,并返回表示第一个新插入元素的迭代器。 | iterator insert(pos,n,elem) |
3.截取其他容器的区间! 在迭代器pos指向的位置的前一个位置插入其他容器(不限于vector!)中位于[first,last)区域中的所有元素(左闭右开哈),并返回表示第一个新插入元素的迭代器。 | iterator insert(pos,first,last) |
4.插入花括号集合! 在迭代器pos指向的位置的前一个位置插入初始化列表中的所有元素,并返回表示第一个新插入元素的迭代器。 | iterator insert(pos,initlist) |
std::vector<int> demo{1,2};
demo.insert(demo.begin() + 1, 3);//{1,3,2}
demo.insert(demo.end(), 2, 5);//{1,3,2,5,5}
std::array<int,3>test{ 7,8,9 };
demo.insert(demo.end(), test.begin(), test.end());//{1,3,2,5,5,7,8,9}
demo.insert(demo.end(), { 10,11 });//{1,3,2,5,5,7,8,9,10,11}
for (int i = 0; i < demo.size(); i++) {
cout << demo[i] << " ";
}
v.insert()复杂度很高,迫不得已不使用
2. 附加 v.push_back()
在vector数组的尾部附加一个元素,push_back只能添加一个元素!不像inser()可以加若干元素。
vecotr<int> demo;
int i=0;
while(i<10){
demo.push_back(i);
i++;
}
3.emplace()&emplace_back()
版权声明:本文为CSDN博主「Tyler_Zx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38289815/article/details/105896622
C++11 新标准引入了三个新成员:emplace_front、emplace 和 emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应 push_front、insert 和 push_back,允许将元素放置在容器头部、一个指定位置之前或容器尾部。
当调用 push 或 insert 成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个 emplace 成员函数时,则是将参数传递给元素类型的构造函数。emplace 成员使用这些参数在容器管理的内存空间中直接构造元素。
emplace 函数的参数根据元素类型而变化,参数必须与元素类型的构造函数相匹配。emplace 函数在容器中直接构造元素。传递给 emplace 函数的参数必须与元素类型的构造函数相匹配。
emplace()
template< class... Args >
iterator emplace( const_iterator pos, Args&&... args ); (since C++11)
将新元素直接插入容器的 pos 之前。元素是通过 std::allocator_traits::construct 构造的,通常使用 placement-new 在容器提供的位置就地构造元素。参数 args... 作为 std::forward < Args > ( args ) ... 转发给构造函数。如果新的 size() 大于 capacity(),则所有迭代器和引用均无效。否则,只有插入点之前的迭代器和引用保持有效。
emplace_back()
template< class... Args >
reference emplace_back( Args&&... args ); (since C++17)
将新元素附加到容器的末尾。该元素是通过 std::allocator_traits::construct 构造的,通常使用 placement-new 在容器提供的位置就地构造该元素。参数 args... 作为 std::forward < Args > ( args ) ... 转发给构造函数。如果新的 size() 大于 capacity(),则所有迭代器和引用(包括过去的迭代器)都将失效。否则,只有过去的迭代器是无效的。
处理基础数据类型:
// reference: http://www.cplusplus.com/reference/vector/vector/emplace_back/
int test()
{
{ /*
template <class... Args>
void emplace_back (Args&&... args);
*/
std::vector<int> myvector = { 10, 20, 30 };
myvector.emplace_back(100);
myvector.emplace_back(200);
std::cout << "myvector contains:";
for (auto& x : myvector)
std::cout << ' ' << x;
std::cout << '\n';
}
{ /*
template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
*/
std::vector<int> myvector = { 10, 20, 30 };
auto it = myvector.emplace(myvector.begin() + 1, 100);
myvector.emplace(it, 200);
myvector.emplace(myvector.end(), 300);
std::cout << "myvector contains:";
for (auto& x : myvector)
std::cout << ' ' << x;
std::cout << '\n';
}
return 0;
}
处理对象:
#include <vector>
#include <string>
#include <iostream>
struct President
{
std::string name;
std::string country;
int year;
President(std::string p_name, std::string p_country, int p_year)
: name(std::move(p_name)), country(std::move(p_country)), year(p_year)
{
std::cout << "I am being constructed.\n";
}
President(President&& other)
: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
{
std::cout << "I am being moved.\n";
}
President& operator=(const President& other) = default;
};
int main()
{
std::vector<President> elections;
std::cout << "emplace_back:\n";
elections.emplace_back("Nelson Mandela", "South Africa", 1994);
std::vector<President> reElections;
std::cout << "\npush_back:\n";
reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));
std::cout << "\nContents:\n";
for (President const& president: elections) {
std::cout << president.name << " was elected president of "
<< president.country << " in " << president.year << ".\n";
}
for (President const& president: reElections) {
std::cout << president.name << " was re-elected president of "
<< president.country << " in " << president.year << ".\n";
}
}
输出:
emplace_back:
I am being constructed.
push_back:
I am being constructed.
I am being moved.
Contents:
Nelson Mandela was elected president of South Africa in 1994.
Franklin Delano Roosevelt was re-elected president of the USA in 1936.
emplace_back() 与 push_back() 对比:
// reference: https://corecplusplustutorial.com/difference-between-emplace_back-and-push_back-function/
class Dat {
int i;
std::string ss;
char c;
public:
Dat(int ii, std::string s, char cc) :i(ii), ss(s), c(cc) { }
~Dat() { }
};
int test_emplace_4()
{
std::vector<Dat> vec;
vec.reserve(3);
vec.push_back(Dat(89, "New", 'G')); // efficiency lesser
//vec.push_back(678, "Newer", 'O'); // error,push_back can’t accept three arguments
vec.emplace_back(890, "Newest", 'D'); // work fine, efficiency is also more
return 0;
}
std::erase & std::erase_if (std::vector)
template< class T, class Alloc, class U >
constexpr typename std::vector<T,Alloc>::size_type
erase(std::vector<T,Alloc>& c, const U& value); (1) (since C++20)
template< class T, class Alloc, class Pred >
constexpr typename std::vector<T,Alloc>::size_type
erase_if(std::vector<T,Alloc>& c, Pred pred); (2) (since C++20)
(1) 从容器中删除所有等于 value 的元素。相当于:
auto it = std::remove(c.begin(), c.end(), value);
auto r = std::distance(it, c.end());
c.erase(it, c.end());
return r;
3.3 删除
在删除的函数中,要注意的点有:使用某个删除函数之后,vector的大小(size)和容量(capacity)会怎么变化?删除之后其余元素会不会向前移动,原下标会不会改变?
1. 删除全部 v.clear()
vector<int> v;
v.clear();
clear 清除容器中的所有元素,调用之后,size() 返回零。使所有引用包含元素的引用,指针或迭代器无效。
2. 🧡删除最后一个元素 v.pop_back()
pop_back() 成员函数的用法非常简单,它不需要传入任何的参数,也没有返回值。
vector<int>demo={ 1,2,3,4,5 };
demo.pop_back();
删除最后一个元素还可以用v.emplace_back(),和push_back()等价
3. 🧡删除部分 v.erase()
v.erase()的用法有两种:
(1) 删除一个! 删除pos位置上的元素 。返回一个指向删除元素所在位置下一个位置的迭代器。 | v.erase(pos) |
(2) 删除区间! 删除范围内的元素 [first, last),左闭右开! | v.erase(pos begin,pos end) |
vector<int> a(10,0);
vector<int> iterator::it=a.erase(a.begin()+1,a.begin()+3);
for(auto c:a){
cout<<c;
}
a.erase(a.begin());
for(auto c:a){
cout<<c;
}
输出:
0 3 4 5 6 7 8 9
3 4 5 6 7 8 9
v.erase() 复杂度很高,迫不得已不使用
4. 删除部分 v.remove() (未写完)
3.4 修改(未写完)
1.改:替换:v.replace()
2.改:排序 v.sort(v.begin().v.end())从小到大
3.改:反转 v.reverse(v.begin(),v.end())
3.5 对多个vector的操作
4.1 交换两个vector v1.swap(other vector)
std::vector<int> v1{1, 2, 3};
std::vector<int> v2{7, 8, 9};
v2.swap(v1);
不同于字符串的交换是swap(s1,s2);
二维数组
1. 二维数组初始化
int m=10, n=20;
vector<vector<char>> map(m, vector<char>(n, '.'));
2. 访问,遍历和修改
map[m][n] = 'Q';
//行的个数
map.size();
//列的个数
map[0].size();
//三种遍历
for (int i = 0; i < map.size(); ++i) {
for (int j = 0; j < map[0].size(); ++j) {
map[i][j] = ',';
map.resize(220);//也可以不写,看起来会自动分配内存
map[11].push_back('a' + i);
}
}
vector<vector<char>> copy;
vector<vector<char>>::iterator it;
for (it = map.begin(); it != map.end(); ++it) {
copy.push_back(*it);//看起来是不能*it=':'的,好像是只读的
}
for (auto c : map) {
c = ':';
}
附一段二维数组遍历,一维数组储存的例子
void reverse_with_iterator(vector<vector<int>> vec)
{
if (vec.empty())
{
cout << "The vector is empty!" << endl;
return;
}
vector<int>::iterator it;
vector<vector<int>>::iterator iter;
vector<int> vec_tmp;
cout << "Use iterator : " << endl;
for (iter = vec.begin(); iter != vec.end(); iter++)
{
vec_tmp = *iter;
for (it = vec_tmp.begin(); it != vec_tmp.end(); it++)
cout << *it << " ";
cout << endl;
}
}
C++ vector 使用详解_Tyler_Zx的博客-CSDN博客