vector

[vector文档](vector - C++ Reference (cplusplus.com))
vector是序列容器,表示可以改变大小的数组。要使用vector,同样需要引入头文件

#include <vector>

vector与string

  • string中会有\0,vector<char>中不会出现\0
  • string可以进行字符串的拼接,vector<char>不可以

vector的构造

void test1() {
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	cout << "v1:";
	for (size_t i = 0; i < v1.size(); ++i) {
		cout << v1[i] << " ";
	}
	cout << endl;

	vector<int> v2(v1);
	cout << "v2:";
	for (size_t i = 0; i < v2.size(); ++i) {
		cout << v2[i] << " ";
	}
	cout << endl;
}

vector的3种遍历方式

operatro[]、迭代器、范围for

void test2() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	//operator[]
	for (size_t i = 0; i < v.size(); ++i) {
		cout << v[i] << " ";
	}
	cout << endl;

	//迭代器
	vector<int>::iterator it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//范围for
	for (auto x : v) {
		cout << x << " ";
	}
	cout << endl;
}

3种类型的迭代器

void test3() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	//正向迭代 可读可写
	vector<int>::iterator it = v.begin();
	while (it != v.end()) {
		cout << *it << " ";
		++it;
	}
	cout << endl;

	//逆向迭代
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend()) {
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
}

//只读
void print_vector(const vector<int>& v) {
	vector<int>::const_iterator it = v.begin();
	while(it != v.end()) {
		//*it = 1;
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

const迭代器单独放到一个函数中,是因为只有const对象才需要const迭代器,在实际中不会直接定义const对象(没有意义),const对象基本都是在传参的过程中产生的,由于传参为了提高效率,基本都会使用&传参,而引用传参如果不改变对象,基本都会加const

容量相关

// 测试vector的默认扩容机制
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v 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.5倍进行增容,但并不是说vector都是按照1.5倍进行增容,具体增容多少是和编译器的不同而有所改变。
还有就是增容的倍数并不是越大越好,倍数越大虽然可以减少增容的次数,但是有可能会导致浪费大量的空间。因此增多少是一种选择,各有利弊。

若是已经确定要存储元素的个数,可以提前将空间设置足够

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';
		}
	}
}

insert()与erase()

void test5() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	v.insert(v.begin(), 0);
	v.insert(v.begin(), -1);
	for (auto x : v) {
		cout << x << " ";
	}
	cout << endl;

	v.erase(v.begin());
	for (auto x : v) {
		cout << x << " ";
	}
	cout << endl;
}

在上面中,erase并不能删除指定的数据,而vector中并没有find函数,所以此时我们需要引入algorithm, #include<algorithm>

//要求删掉2
vector<int>::iterator pos = find(v.begin(), v.end(), 2);
if (pos != v.end()) {
	v.erase(pos);
}
for (auto x : v) {
	cout << x << " ";
}
cout << endl;

find其实是一个函数模板,如下

template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& val) {
	while (first != last) {
		if (*first == val) return first;
		++first;
	}
	return last;
}

迭代器失效

迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

  1. 引起底层空间改变的操作,迭代器可能失效

    void test6() {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(2);
    	v.push_back(3);
    	v.push_back(4);
    //迭代器失效
    	vector<int>::iterator it = v.begin();
    	v.push_back(5);
    	v.push_back(6);
    
    	while (it != v.end()) {
    		cout << *it << " ";
    		++it;
    	}
    	cout << endl;
    }
    

    从上面来看,由于在插入56的之前it已经被赋值,当插入56时,由于空间不够,需要开辟新的空间,销毁原来的空间,而it任然指向的是原来的那个空间,因此此时的迭代器就已经失效了。

  2. 删除操作——erase

    void test7() {
    	vector<int> v;
    	v.push_back(1);
    	v.push_back(2);
    	v.push_back(3);
    	v.push_back(4);
    	v.push_back(5);
    	v.push_back(6);
    
    	vector<int>::iterator it = v.begin();
    
    	for (auto x : v) {
    		cout << x << " ";
    	}
    	cout << endl;
    	//删除偶数
    	while (it != v.end()) {
    		if (*it % 2 == 0) {
    			v.erase(it);
    		}
            else {
                ++it;        
            }
    	}
    
    	for (auto x : v) {
    		cout << x << " ";
    	}
    	cout << endl;
    }
    

    在上面代码中,由于使用erase删除pos位置元素的时候,pos之后的元素会向前移动,此时的it没有改变,但是it所指向的元素发生了变化,变成了原来pos+1位置的元素,此时程序就崩溃了。而之后又要进行++it,因此就会漏掉对此时it所指向元素的判断。

    注意:在vscode中以上写法会导致程序崩溃,但在linux下的g++中,以上写法并不会崩溃,只是最后的结果会出错。

    因为erase返回的是被删除元素后一个位置的迭代器,所以正确的写法如下

    	while (it != v.end()) {
    		if (*it % 2 == 0) {
    			it = v.erase(it);
    		}
    		else {
    			++it;
    		}
    	}
    
posted @   羡鱼OvO  阅读(89)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示