vector


vector 容器是 STL 中最常用的容器之一,它和 array 容器非常类似,都可以看做是对 C++ 普通数组的“升级版”。不同之处在于,array 实现的是静态数组(容量固定的数组),而 vector 实现的是一个动态数组,即可以进行元素的插入和删除,在此过程中,vector 会动态调整所占用的内存空间,整个过程无需人工干预。

vector 常被称为向量容器,因为该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为O(1);而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶O(n)。

vector的创建

#include<iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> values;
    vector<int> values;
    vector<int> vec2(20);//有20个元素,默认值为0
    vector<int> vec3(20, 1.0);//有20个元素,默认值为1.0
    vector<int> primes{2, 3, 5, 7, 11, 13, 17, 19};
    vector<char> vec4(5, 'c');
    vector<char> vec5(vec4);
    int array[] = {1, 2, 3};
    vector<int> vec6(array, array + 2);//保存{1, 2}
    vector<int> vec7(begin(primes), begin(primes) + 3);//保存{2, 3, 5};
    return 0;
}

运行结果

values capacity : 20
values size: 0

迭代器

成员函数功能
begin()返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。
end()返回指向容器最后一个元素之后一个位置的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin() 搭配使用。
rbegin()返回指向最后一个元素的反向迭代器;如果是 const 类型容器,在该函数返回的是常量反向迭代器。
rend()返回指向第一个元素之前一个位置的反向迭代器。如果是 const 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 rbegin() 搭配使用。
cbegin()和 begin() 功能类似,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素。
cend()和 end() 功能相同,只不过其返回的迭代器类型为常量正向迭代器,不能用于修改元素。
crbegin()和 rbegin() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素。
crend()和 rend() 功能相同,只不过其返回的迭代器类型为常量反向迭代器,不能用于修改元素。

在这里插入图片描述

begin(), end()

代码演示

#include<iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> values1{1, 2, 3, 4, 5};
    auto first1 = values1.begin();//或者first = begin(values);
    auto end1 = values1.end();//或者end = end(values);
    *first1 = 20;
    while(first1 != end1) {
        cout << *first1 << " ";
        ++first1;
    }
    cout << endl;
    return 0;
}

运行结果

20 2 3 4 5 

cbgin(), cend()

代码演示

int main() {
    vector<int> values2{1, 2, 3, 4, 5};
    auto first2 = values2.cbegin();
    auto end2 = values2.cend();
    *first2 = 20;
    while(first2 != end2) {
        cout << *first2 << " ";
        ++first2;
    }
    cout << endl;

    return 0;
}

运行结果

cbegin.cpp:16:15: error: assignment of read-only location ‘first2.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator*<const int*, std::vector<int> >()*first2 = 20;
               ^~

rbegin(), rend()

代码演示

#include<iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> values{1, 2, 3, 4, 5};
    auto first = values.rbegin();
    auto end = values.rend();
    *first = 20;
    while(first != end) {
        cout << *first << " ";
        ++first;
    }
    cout << endl;

    return 0;
}

运行结果

20 4 3 2 1 

容量

empty()

函数
bool empty()

功能
检查容器是否无元素,即是否 begin() == end() 。

参数
(无)

返回值
若容器为空则为 true ,否则为 false

size()

返回容纳的元素数

max_size()

返回可容纳的最大元素数 ,最大容器

reserve()

函数
constexpr void reserve( size_type new_cap );

增加 vector 的容量到大于或等于 new_cap 的值。若 new_cap 大于当前的 capacity() ,则分配新存储,否则该方法不做任何事。

reserve() 不更改 vector 的 size 。

若 new_cap 大于 capacity() ,则所有迭代器,包含尾后迭代器和所有到元素的引用都被非法化。否则,没有迭代器或引用被非法化。

参数
new_cap - vector 的新容量

capacity()

功能:
返回容器当前已为之分配空间的元素数。

函数:
size_type capacity();

参数
(无)

返回值
当前分配存储的容量。

代码

#include <iostream>
#include <vector>

void print_vec(std::vector<int> &vec) {
    for (auto i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
}

int main()
{
    int sz = 200;
    std::vector<int> v1;
 
    auto cap = v1.capacity();
    std::cout << "initial capacity=" << cap << '\n';
 
    for (int n = 0; n < sz; ++n) {
        v1.push_back(n);
        if (cap != v1.capacity()) {
            cap = v1.capacity();
            std::cout << "new capacity=" << cap << '\n';
            print_vec(v1);
        }
    }
 
    std::cout << "final size=" << v1.size() << '\n';
    std::cout << "final capacity=" << v1.capacity() << '\n';
}

运行结果

initial capacity=0
new capacity=1
0 
new capacity=2
0 1 
new capacity=4
0 1 2 
new capacity=8
0 1 2 3 4 
new capacity=16
0 1 2 3 4 5 6 7 8 
new capacity=32
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
new capacity=64
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 
new capacity=128
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 
new capacity=256
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 
final size=200
final capacity=256

size(),capacity(),max_size()的不同

size()返回容器内元素的个数,capacity()返回容器空间大小

#include<iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> values;
    values.reserve(20);
    auto cap = values.capacity();
    auto s = values.size();
    auto max_size = values.max_size();
    cout << "values capacity : " << cap << endl;
    cout << "values size: " << s << endl;
    cout << "values max_size :" << max_size << endl;
    return 0;
}
values capacity : 20
values size: 0
values max_size :4611686018427387903

修改器

insert()

功能
insert() 函数的功能是在 vector 容器的指定位置插入一个或多个元素。

函数
该函数的语法格式有多种,如表 1 所示。

						表 1 insert() 成员函数语法格式
语法格式用法说明
iterator
insert(pos,elem)
在迭代器 pos 指定的位置之前插入一个新元素elem,并返回表示新插入元素位置的迭代器。
iterator
insert(pos,n,elem)
在迭代器 pos 指定的位置之前插入 n 个元素 elem,并返回表示第一个新插入元素位置的迭代器。
iterator
insert(pos,first,last)
在迭代器 pos 指定的位置之前,插入其他容器(不仅限于vector)中位于 [first,last) 区域的所有元素,并返回表示第一个新插入元素位置的迭代器。
iterator
insert(pos,initlist)
在迭代器 pos 指定的位置之前,插入初始化列表(用大括号{}括起来的多个元素,中间有逗号隔开)中所有的元素,并返回表示第一个新插入元素位置的迭代器。

代码

#include<iostream>
#include<vector>
using namespace std;

void print_vec(vector<int> &vec) {
    for (int i = 0; i < vec.size(); i++) {
        cout << vec[i] << " ";
    }
    cout << endl;
}
int main() {
    vector<int> a;
    cout << "a is empty? -- " << a.empty() << endl;
    auto it = a.begin();
    it = a.insert(it, 2);
    it = a.insert(it, 3);
    it = a.insert(it, 4); 
    cout << "a is empty? -- " << a.empty() << endl;
    print_vec(a);
    it = a.insert(it, 2, 200);
    print_vec(a);
    vector<int> b(3, 400);
    a.insert(it + 2, b.begin(), b.end());
    print_vec(a);
    int arr[] = {211, 223, 224};
    a.insert(a.begin(), arr, arr + 3);
    print_vec(a);
    return 0;
}

运行结果

a is empty? -- 1
a is empty? -- 0
4 3 2 
200 200 4 3 2 
200 200 400 400 400 4 3 2 
211 223 224 200 200 400 400 400 4 3 2 

emplace()

emplace() 是 C++ 11 标准新增加的成员函数,用于在 vector 容器指定位置之前插入一个新的元素。

既然 emplace() 和 insert() 都能完成向 vector 容器中插入新元素,那么谁的运行效率更高呢?答案是 emplace()因此,在实际使用中,推荐大家优先使用 emplace()。

再 次 强 调 , e m p l a c e ( ) 每 次 只 能 插 入 一 个 元 素 , 而 不 是 多 个 . \color{red}{再次强调,emplace() 每次只能插入一个元素,而不是多个.} emplace()

函数
iterator emplace (const_iterator pos, args…);

其中,pos 为指定插入位置的迭代器;args… 表示与新插入元素的构造函数相对应的多个参数;该函数会返回表示新插入元素位置的迭代器。

push_back()和emplace_back()

函数
constexpr void push_back( T&& value );
constexpr reference emplace_back( Args&&… args )
后附给定元素 value 到容器尾。

  1. 初始化新元素为 value 的副本。
  2. 移动 value 进新元素。

代码演示

#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
using namespace std;
int main() {
    vector<int> values;
    values.push_back(1);
    values.push_back(2);
    for (int i = 0; i < values.size(); i++) {
        cout << values[i] << " ";
    }
    cout << endl;
    vector<int> values1;
    values1.emplace_back(1);
    values1.emplace_back(2);
    for (int i = 0; i < values1.size(); i++) {
        cout << values1[i] << " ";
    }
    cout << endl;

  return 0;
}

运行结果

1 2 
1 2 

push_back()和emplace_back()的区别

emplace_back() 和 push_back() 的区别,就在于底层实现的机制不同。push_back() 向容器尾部添加元素时,首先会创建这个元素,然后再将这个元素拷贝或者移动到容器中(如果是拷贝的话,事后会自行销毁先前创建的这个元素);而 emplace_back() 在实现时,则是直接在容器尾部创建这个元素,省去了拷贝或移动元素的过程。

显然完成同样的操作,push_back() 的底层实现过程比 emplace_back() 更繁琐,换句话说,emplace_back() 的执行效率比 push_back() 高。因此,在实际使用时,建议大家优先选用 emplace_back()。

resize()

功能: 改变容器中可存储元素的个数 .
重设容器大小以容纳 count 个元素。
若当前大小大于 count ,则减小容器为其首 count 个元素。

函数:
void resize( size_type count )//将原vector变成count大小的vector.新元素的值默认为0.
void resize( size_type count, T value = T() );/将原vector变成count大小的vector.新元素的值默认为value.

参数
count - 容器的大小
value - 用以初始化新元素的值

代码

#include<iostream>
#include<vector>
using namespace std;

int main() {
    vector<int> c = {1, 2, 3};
    for (int i = 0; i < c.size(); i++) {
        cout << c[i] << " ";
    }
    cout << endl;
    c.resize(5, 3);
    for (int i = 0; i < c.size(); i++) {
        cout << c[i] << " ";
    }
    cout << endl;
    c.resize(2);
    for (int i = 0; i < c.size(); i++) {
        cout << c[i] << " ";
    }
    cout << endl;
}

运行结果

1 2 3 
1 2 3 3 3 
1 2 

删除

表 1 删除 vector 容器元素的几种方式

函数功能
pop_back()删除 vector 容器中最后一个元素,该容器的大小(size)会减 1,但容量(capacity)不会发生改变。
erase(pos)删除 vector 容器中 pos 迭代器指定位置处的元素,并返回指向被删除元素下一个位置元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会发生改变。
swap(beg)、pop_back()先调用 swap() 函数交换要删除的目标元素和容器最后一个元素的位置,然后使用 pop_back() 删除该目标元素。
erase(beg,end)删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个位置元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会发生改变。
remove()删除容器中所有和指定元素值相等的元素,并返回指向最后一个元素下一个位置的迭代器。值得一提的是,调用该函数不会改变容器的大小和容量。
clear()删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会改变 vector 的大小(变为 0),但不是改变其容量。

代码演示

#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
#include <algorithm>
using namespace std;

void out_all(vector<int> &vec) {
    cout << "size: " << vec.size() << endl;
    cout << "capacity: " << vec.capacity() << endl;
    for (int i = 0; i < vec.size(); i++) {
        cout << vec[i] << " ";
    }
    cout << endl << endl;
}

int main() {
    vector<int> demo{ 1, 2, 3, 4, 4, 5, 6, 4, 5, 6, 4,  7, 8, 9, 10 };
    out_all(demo);
    
    cout << "pop_back()-删除末尾元素 :" << endl;
    demo.pop_back();
    out_all(demo);
    
    cout << "erase(demo.begin() + 1)-删除第二个元素 :" << endl;
    demo.erase(demo.begin() + 1);//删除第二个元素,demo.erase(1)是错的
    out_all(demo);
    cout << "erase(demo.begin() + 1, demo.end() + 4)-删除第二到第五之间的所有元素" << endl;
    demo.erase(demo.begin() + 1, demo.begin() + 4);
    out_all(demo);



    cout << "swap()-交换" << endl;
    swap(*(begin(demo) + 1), *(end(demo) - 1));
    out_all(demo);
    
    //另外还可以看到,既然通过 remove() 函数删除掉 demo 容器中的多个指定元素,该容器的大小和容量都没有改变,其剩余位置还保留了之前存储的元素。我们可以使用 erase() 成员函数删掉这些 "无用" 的元素。

    cout << "remove(beg, end, val)-删除指定范围值为val的元素" << endl;//要加上<algorithm> 头文件
    auto iter = remove(demo.begin(), demo.end(), 4);
    out_all(demo);
    demo.erase(iter, demo.end());
    out_all(demo);
    
    cout << "clear()-清空容器" << endl;
    demo.clear();
    out_all(demo);

    return 0;
}

运行效果

size: 15
capacity: 15
1 2 3 4 4 5 6 4 5 6 4 7 8 9 10 

pop_back()-删除末尾元素 :
size: 14
capacity: 15
1 2 3 4 4 5 6 4 5 6 4 7 8 9 

erase(demo.begin() + 1)-删除第二个元素 :
size: 13
capacity: 15
1 3 4 4 5 6 4 5 6 4 7 8 9 

erase(demo.begin() + 1, demo.end() + 4)-删除第二到第五之间的所有元素
size: 10
capacity: 15
1 5 6 4 5 6 4 7 8 9 

swap()-交换
size: 10
capacity: 15
1 9 6 4 5 6 4 7 8 5 

remove(beg, end, val)-删除指定范围值为val的元素
size: 10
capacity: 15
1 9 6 5 6 7 8 5 8 5 

size: 8
capacity: 15
1 9 6 5 6 7 8 5 

clear()-清空容器
size: 0
capacity: 15

swap:

#include <iostream>
#include <vector>
 
template<class Os, class Co> Os& operator<<(Os& os, const Co& co) {
    os << "{";
    for (auto const& i : co) { os << ' ' << i; }
    return os << " } ";
}
 
int main()
{
    std::vector<int> a1{1, 2, 3}, a2{4, 5};
 
    auto it1 = std::next(a1.begin());
    auto it2 = std::next(a2.begin());
 
    int& ref1 = a1.front();
    int& ref2 = a2.front();
 
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
    a1.swap(a2);
    std::cout << a1 << a2 << *it1 << ' ' << *it2 << ' ' << ref1 << ' ' << ref2 << '\n';
 
    // 注意交换后迭代器与引用保持与其原来的元素关联,例如指向 'a1' 中值为 2 的元素的 it1 仍指向同一元素,
    // 尽管此元素被移动到 'a2' 中。
}

输出:


{ 1 2 3 } { 4 5 } 2 5 1 4
{ 4 5 } { 1 2 3 } 2 5 1 4

访问(at, data, front, back, operator[])

at访问指定的元素,同时进行越界检查 (公开成员函数)
operator[]访问指定的元素 (公开成员函数)
front访问第一个元素 (公开成员函数)
back访问最后一个元素 (公开成员函数)
data返回指向内存中数组第一个元素的指针
#include<iostream>
#include<vector>
#include<cstdio>
#include<string>
using namespace std;

void out_all (vector<int> &nums) {
    for (int i = 0; i < nums.size();i++) {
        cout << nums[i] << " ";
    }
    cout << endl;
}
int main() {
    vector<int> nums{1, 2, 3, 4, 5, 6, 7};
    out_all(nums);
    cout << endl;
    cout << "front() : "<<nums.front() << endl;
    cout << "back() : " << nums.back() << endl;
    cout << "nums[3] :" << nums[3] << endl;
    cout << "data() : " << nums.data() << endl;

    nums.at(1) = 88;
    out_all(nums);
    cout << "nums(2) : " << nums.at(2) << endl;

    try {
        nums.at(10) = 666;
    } catch (out_of_range const& exc) {
        cout << exc.what() << endl;
    }
    out_all(nums);
    return 0;
}
1 2 3 4 5 6 7 

front() : 1
back() : 7
nums[3] :4
data() : 0x55ed0a134c20
1 88 3 4 5 6 7 
nums(2) : 3
vector::_M_range_check: __n (which is 10) >= this->size() (which is 7)
1 88 3 4 5 6 7 
```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值