c++ STL之vector基本使用


本质

内部是一个数组,增加和删除的时候涉及到大量元素移动、复制,所以耗时
数组大小可变,当插入操作超过默认大小,会重新分布内存
内部维护的是拷贝的数据,对原数据进行操作,不会更改vector内部数据

头文件

#include <vector>
需要使用std 命名空间

增加

定义 vector<int> test{1, 2, 3, 4};
1.在尾部直接插入元素
test.push_back(1);
2.使用迭代器,第一个参数传入一个指向当前vector的迭代器,第二个参数传入值
test.insert(test.begin(), 1); //在头部插入
有多个重载函数:
   填充指定个数的元素
   test.insert(test.begin(), 10, 1); //第一个参数是迭代器位置,第二个参数是个数,第三个参数是值
   插入迭代器范围的数据
   test.insert(test.begin(), test.begin(), test.end());
   第一个参数是插入迭代器位置,第二个参数和第三个参数是范围,左闭右开
3.值得注意的是,由于vector是可变的,像vector插入后,可能使所有指向vector的指针、迭代器失效
当添加到一定大小,vector就会重新分配空间,将旧的空间元素拷贝到新空间中,释放旧空间
4.函数的参数的迭代器由于3的原因可能失效,但是返回值一定不会失效
看源码可知返回值使用begin() + __offset,而不是传入的参数迭代器,就是因为可能内存重新分配

如果你在做一个循环插入或者赋值的首推荐

#include <iostream>
#include <vector>
using namespace std;
int main() {
    vector<int> test{1, 2, 3, 4};
    for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
        if(*test_iterator == 3) {
            test_iterator = test.insert(test_iterator, 4);
            if( test_iterator + 1 == test.end()) {
                break;                
            }
            test_iterator++;
        }
    }

    return 0;
}

当满足条件插入后,防止迭代器失效,使用insert的返回值进行重新赋值,之后的 test_iterator++;是因为test_iterator当前指向4,如果不连着加两次会陷入死循环,下一个再加就到了4

删除

1.删除尾部元素
test.pop_back(); 
2.使用迭代器
test.erase(test.begin());  //参数为迭代器位置,返回值为迭代器位置
多个重载函数
test.erase(test.begin(), test.end() - 1);   //删除迭代器的范围元素,左闭右开
3.迭代器循环删除,这个是比较有争议的
对于erase的返回值:
An iterator pointing to the next element (or end()).
指向下一个元素的迭代器

关于erase有详述
本人这里认为返回的迭代器就是指向的你删除元素之后的元素,注意的是迭代器本身没有改变,只不过是元素迁移了

循环删除推荐

#include <iostream>
#include <vector>
using namespace std;
int main() {
    vector<int> test{1, 2, 3, 4};

    
    for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end();) {
        if(*test_iterator == 3) {
            test_iterator = test.erase(test_iterator);
        }
        else {
            test_iterator++;
        }
    }

    return 0;
}

4.网上好多提到remove函数
千篇一律都是remove和erase搭配,我erase明明就可以实现,要remove干嘛呢?
为了删除范围内所有的指定元素,erase函数只能删除单个的,要不就是一个范围,没有remove这种条件的删除

 remove不是成员函数,不能真正的删除
 这里先说__remove_if,remove本质也是__remove_if
 __remove_if是有条件的删除,第一个参数和第二个参数代表范围,第三个参数构建一个value值的对象
 然后在__remove_if内部对给定值比较,做了一个for循环赋值,把不等于给定值的都移动到前面
 这样到最后,把等于给定值的第一个迭代器返回
 这就是remove的核心,的确不能直接删除元素,但是remove对整个迭代器区间的元素进行了重新赋值分配,划分了两拨,前面是不含有给定值的,后面是含有给定值的来个图片

之后就是配合erase的迭代器区间删除函数就可以了
remove头文件是#include <algorithm>

例子

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


int main() {
    vector<int> test{1,3,3,3,4,3};

    for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
        std::cout << *test_iterator << std::endl;
    }

    test.erase(remove(test.begin(), test.end(), 3), test.end());

    for(vector<int>::iterator test_iterator = test.begin(); test_iterator != test.end(); test_iterator++) {
        std::cout << *test_iterator << std::endl;
    }
    //删除前1,3,3,3,4,3
    //删除后1,4

    return 0;
}

访问和改动

1.使用迭代器进行修改
STL中迭代器有两种,一种是const_iterator,一种是iterator,区别就是const_iterator只能读取和调用const相关的函数,iterator都可以
本质就是const和非const的区别
我们可以使用迭代器-> 调用迭代器指向的内存变量的函数,迭代器-> 和 内存变量. 的操作是一样的
也可以使用 *迭代器. 的操作,这样就是拿到迭代器指向的变量然后操作
2.c.back(); //返回c中尾元素的引用,如果c为空,函数未定义
3.c.front(); //返回c中首元素的引用,如果c为空,函数未定义
4.c[n]; //返回c中下标为n的元素引用,如果n>=c.size(),行为未定义
5.c.at[n]; //返回下标为n的元素引用,如果下标越界,抛出异常

这些访问元素的成员函数返沪的都是引用,容器是const,返回的是const引用,不是const,返回普通引用。内部根据const重载了访问函数

添加删除都要考虑迭代器失效问题

使用insert和erase返回值更新迭代器


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM