c++---vector介绍

先点赞后观看哦!!!谢谢大家!

1.vector的使用说明

1.1vector的介绍

http://www.cplusplus.com/reference/vector/vector/
使用 STL 的三个境界:能用,明理,能扩展 ,那么学习 vector ,我们也是按照这个方法去学
习。

1.2vector的使用

1.2.1vector的定义

1.2.2vector literator的使用

1.2.3vector空间增长问题


1.capacity 的代码在 vs 和 g++ 下分别运行会发现, vs capacity 是按 1.5 倍增长的, g++ 是按 2
倍增长的 。这个问题经常会考察,不要固化的认为, vector 增容都是 2 倍,具体增长多少是
根据具体的需求定义的。 vs 是 PJ 版本 STL , g++ 是 SGI 版本 STL 。
2.reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代
价缺陷问题。
3.resize 在开空间的同时还会进行初始化,影响 size 。
// 如果已经确定 vector 中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
void TestVectorExpandOP ()
{
vector < int > v ;
size_t sz = v . capacity ();
v . reserve ( 100 ); // 提前将容量设置好,可以避免一遍插入一遍扩容
cout << "making bar grow:\n" ;
for ( int i = 0 ; i < 100 ; ++ i )
{
v . push_back ( i );
if ( sz != v . capacity ())
{
sz = v . capacity ();
cout << "capacity changed: " << sz << '\n' ;
}
}
}

1.2.3vector增删改查

1.2.4vector迭代器失效问题(重点)

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对
指针进行了封装 ,比如: vector 的迭代器就是原生态指针 T* 。因此 迭代器失效,实际就是迭代器
底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间 ,造成的后果是程序崩溃 ( 即
如果继续使用已经失效的迭代器,程序可能会崩溃 ) 。
对于 vector 可能会导致其迭代器失效的操作有:

  1. 会引起其底层空间改变的操作,都有可能是迭代器失效 ,比如: resize 、 reserve 、 insert 、
    assign 、 push_back 等。
    #include <iostream>
    using namespace std ;
    #include <vector>
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 , 5 , 6 };
    auto it = v . begin ();
    // 将有效元素个数增加到 100 个,多出的位置使用 8 填充,操作期间底层会扩容
    // v.resize(100, 8);
    // reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容
    量改变
    // v.reserve(100);
    // 插入元素期间,可能会引起扩容,而导致原空间被释放
    // v.insert(v.begin(), 0);
    // v.push_back(8);
    // 给 vector 重新赋值,可能会引起底层容量改变
    v . assign ( 100 , 8 );
    /*
    出错原因:以上操作,都有可能会导致vector 扩容,也就是说 vector 底层原理旧空间被释
    放掉,而在打印时,it 还使用的是释放之间的旧空间,在对 it迭代器操作时,实际操作的是
    一块已经被释放的空间,而引起代码运行时崩溃。
    解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector 中的元素,只需给
    it重新赋值即可。
    */
    while ( it != v . end ())
    {
    cout << * it << " " ;
    ++ it ;
    }
    cout << endl ;
    return 0 ;
    }
  2. 指定位置元素的删除操作 - -erase、
    int main ()
    {
    int a [] = { 1 , 2 , 3 , 4 };
    vector < int > v ( a , a + sizeof ( a ) / sizeof ( int ));
    // 使用 find 查找 3 所在位置的 iterator
    vector < int > :: iterator pos = find ( v . begin (), v . end (), 3 );
    // 删除 pos 位置的数据,导致 pos 迭代器失效。
    v . erase ( pos );
    cout << * pos << endl ; // 此处会导致非法访问
    return 0 ;
    }
    erase 删除 pos 位置元素后, pos 位置之后的元素会往前搬移,没有导致底层空间的改变,理
    论上讲迭代器不应该会失效,但是:如果 pos 刚好是最后一个元素,删完之后 pos 刚好是 end
    的位置,而 end 位置是没有元素的,那么 pos 就失效了。因此删除 vector 中任意位置上元素
    时, vs 就认为该位置迭代器失效了。
    以下代码的功能是删除 vector 中所有的偶数,请问那个代码是正确的,为什么?
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 };
    auto it = v . begin ();
    while ( it != v . end ())
    {
    if ( * it % 2 == 0 )
    v . erase ( it );
    ++ it ;
    }
    return 0 ;
    }
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 };
    auto it = v . begin ();
    while ( it != v . end ())
    {
    if ( * it % 2 == 0 )
    it = v . erase ( it );
    else
    ++ it ;
    }
    return 0 ;
    }
  3. 注意: Linux 下, g++ 编译器对迭代器失效的检测并不是非常严格,处理也没有 vs 下极端。
    // 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 , 5 };
    for ( size_t i = 0 ; i < v . size (); ++ i )
    cout << v [ i ] << " " ;
    cout << endl ;
    auto it = v . begin ();
    cout << " 扩容之前, vector 的容量为 : " << v . capacity () << endl ;
    // 通过 reserve 将底层空间设置为 100 ,目的是为了让 vector 的迭代器失效
    v . reserve ( 100 );
    cout << " 扩容之后, vector 的容量为 : " << v . capacity () << endl ;
    // 经过上述 reserve 之后, it 迭代器肯定会失效,在 vs 下程序就直接崩溃了,但是 linux
    下不会
    // 虽然可能运行,但是输出的结果是不对的
    while ( it != v . end ())
    {
    cout << * it << " " ;
    ++ it ;
    }
    cout << endl ;
    return 0 ;
    }
    程序输出:
    1 2 3 4 5
    扩容之前, vector 的容量为 : 5
    扩容之后, vector 的容量为 : 100
    0 2 3 4 5 409 1 2 3 4 5
    // 2. erase 删除任意位置代码后, linux 下迭代器并没有失效
    // 因为空间还是原来的空间,后序元素往前搬移了, it 的位置还是有效的
    #include <vector>
    #include <algorithm>
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 , 5 };
    vector < int > :: iterator it = find ( v . begin (), v . end (), 3 );
    v . erase ( it );
    cout << * it << endl ;
    while ( it != v . end ())
    {
    cout << * it << " " ;
    ++ it ;
    }
    cout << endl ;
    return 0 ;
    }
    程序可以正常运行,并打印:
    4
    4 5
    // 3: erase 删除的迭代器如果是最后一个元素,删除之后 it 已经超过 end
    // 此时迭代器是无效的, ++it 导致程序崩溃
    int main ()
    {
    vector < int > v { 1 , 2 , 3 , 4 , 5 };
    // vector<int> v{1,2,3,4,5,6};
    auto it = v . begin ();
    while ( it != v . end ())
    {
    if ( * it % 2 == 0 )
    v . erase ( it );
    ++ it ;
    }
    for ( auto e : v )
    cout << e << " " ;
    cout << endl ;
    return 0 ;
    }
    ========================================================
    // 使用第一组数据时,程序可以运行

sly@VM - 0 - 3 - centos 20220114 \] $ g ++ testVector . cpp - std = c ++ 11 \[ sly@VM - 0 - 3 - centos 20220114 \] $ . / a . out 1 3 5 ========================================================= // 使用第二组数据时,程序最终会崩溃 \[ sly@VM - 0 - 3 - centos 20220114 \] $ vim testVector . cpp \[ sly@VM - 0 - 3 - centos 20220114 \] $ g ++ testVector . cpp - std = c ++ 11 \[ sly@VM - 0 - 3 - centos 20220114 \] $ . / a . out Segmentation fault 从上述三个例子中可以看到: SGI STL 中,迭代器失效后,代码并不一定会崩溃,但是运行 结果肯定不对,如果 it 不在 begin 和 end 范围内,肯定会崩溃的。 4. 与 vector 类似, string 在插入 + 扩容操作 +erase 之后,迭代器也会失效 #include \ void TestString () { string s ( "hello" ); auto it = s . begin (); // 放开之后代码会崩溃,因为 resize 到 20 会 string 会进行扩容 // 扩容之后, it 指向之前旧空间已经被释放了,该迭代器就失效了 // 后序打印时,再访问 it 指向的空间程序就会崩溃 //s.resize(20, '!'); while ( it != s . end ()) { cout \<\< \* it ; ++ it ; } cout \<\< endl ; it = s . begin (); while ( it != s . end ()) { it = s . erase ( it ); // 按照下面方式写,运行时程序会崩溃,因为 erase(it) 之后 // it位置的迭代器就失效了 // s.erase(it); ++ it ; } } **迭代器失效解决办法:在使用前,对迭代器重新赋值即可** 。 ## 2.vector深度刨析及模拟实现 ![](https://i-blog.csdnimg.cn/direct/d47389c834194f68ada4ac3c357bcdb4.jpeg) ![](https://i-blog.csdnimg.cn/direct/c6d53b9211e04e229e699084da39406d.png) ### 2.1std::vector的框架接口的模拟实现zzh::vector [https://gitee.com/zhejiang-daniel-wu/my_c_code/blob/master/text_09_25/text_09_25/vector.h](https://gitee.com/zhejiang-daniel-wu/my_c_code/blob/master/text_09_25/text_09_25/vector.h "https://gitee.com/zhejiang-daniel-wu/my_c_code/blob/master/text_09_25/text_09_25/vector.h") ### 2.2使用memcpy拷贝问题 假设模拟实现的 vector 中的 reserve 接口中,使用 memcpy 进行的拷贝,以下代码会发生什么问 题? int main () { zzh::vector \< bite::string \> v ; v . push_back ( "1111" ); v . push_back ( "2222" ); v . push_back ( "3333" ); return 0 ; } 问题分析: 1. memcpy 是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存 空间中 2. 如果拷贝的是自定义类型的元素, memcpy 既高效又不会出错,但如果拷贝的是自定义类型 元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为 memcpy 的拷贝实际是浅 拷贝。 ![](https://i-blog.csdnimg.cn/direct/60b9a701a1ae4903804c3ada8c78ebb8.jpeg) ![](https://i-blog.csdnimg.cn/direct/fd510ba369cf4d28a34ded5309ce4f6b.jpeg) **结论:如果对象中涉及到资源管理时,千万不能使用** **memcpy** **进行对象之间的拷贝,因为** **memcpy** **是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。** ### **2.2动态二维数组理解** // 以杨慧三角的前 n 行为例:假设 n 为 5 void test2vector ( size_t n ) { // 使用 vector 定义二维数组 vv , vv 中的每个元素都是 vector\ bit::vector \< bit::vector \< int \>\> vv ( n ); // 将二维数组每一行中的 vecotr\ 中的元素全部设置为 1 for ( size_t i = 0 ; i \< n ; ++ i ) vv \[ i \]. resize ( i + 1 , 1 ); // 给杨慧三角出第一列和对角线的所有元素赋值 for ( int i = 2 ; i \< n ; ++ i ) { for ( int j = 1 ; j \< i ; ++ j ) { vv \[ i \]\[ j \] = vv \[ i - 1 \]\[ j \] + vv \[ i - 1 \]\[ j - 1 \]; } } } zzh::vector\\> vv(n) ; 构造一个 vv 动态二维数组, vv 中总共有 n 个元素,每个元素 都是 vector 类型的,每行没有包含任何元素,如果 n 为 5 时如下所示: ![](https://i-blog.csdnimg.cn/direct/b071aa3d9be640f5bfcfd0bab953aa8d.jpeg) ![](https://i-blog.csdnimg.cn/direct/8346bf7f68004b25b641a7269d34c267.jpeg)

相关推荐
阿里嘎多学长2 小时前
2026-04-05 GitHub 热点项目精选
开发语言·程序员·github·代码托管
xiaoye-duck2 小时前
《算法题讲解指南:递归,搜索与回溯算法--综合练习》--14.找出所有子集的异或总和再求和,15.全排列Ⅱ,16.电话号码的字母组合,17.括号生成
c++·算法·深度优先·回溯
茉莉玫瑰花茶2 小时前
数据结构 - 并查集
数据结构
汀、人工智能2 小时前
05 - 函数基础
数据结构·算法·数据库架构·05 - 函数基础
Makoto_Kimur2 小时前
Java 打印模板大全
java·开发语言·排序算法
程序员榴莲2 小时前
Java(十)super关键字
java·开发语言
HAPPY酷2 小时前
Python高级架构师之路——从原理到实战
java·python·算法
枫叶林FYL2 小时前
第9章 因果推理与物理理解
人工智能·算法·机器学习
Tanecious.2 小时前
蓝桥杯备赛:Day5-P1706 全排列问题
c++·蓝桥杯