【C++】_vector定义、_vector常用方法解析

不管心情如何,不论今天过得怎么样,无论身在何方,请记得...微笑!💓💓💓

  ✨说在前面

亲爱的读者们大家好!💖💖💖,我们又见面了,上一篇文章我给大家介绍了一下stiring类的定义、常用接口以及模拟实现。如果大家没有掌握好相关的知识,上一篇篇文章讲解地很详细,可以再回去看看,复习一下,再进入今天的内容。

我们今天简单给大家讲解一下STL中的一员——vector。vector是向量的意思,在C++中我们用它来表示顺序表。如果大家准备好了,那就接着往下看吧~

  👇👇👇
💘💘💘知识连线时刻(直接点击即可)

【C++】_string类字符串万字详细解析

  🎉🎉🎉复习回顾🎉🎉🎉

         

 博主主页传送门:愿天垂怜的博客

 ​​​​​

 ​​​​​​

🍋知识点一:什么是vector?

•🌰1.vector的定义

vector是 C++ 标准模板库(STL)中的一个非常重要的容器,它提供了一种动态数组的实现。与普通的数组相比,vector可以在运行时动态地增加或减少其大小,而无需程序员手动管理内存。这使得vector成为处理大小可能变化的序列数据的首选容器之一。

我们可以模拟实现vector如下 :

template<class T>
class vector
{
public:
    typedef T* iterator;
    typedef const T* const_iterator;
    //...
private:
    iterator _start = nullptr;
    iterator _finish = nullptr;
    iterator _end_of_storage = nullptr;
}

其中_start和_finish分别是指向有效长度头和尾的指针,_end_of_storage是指向空间末尾的指针。 

​​​​​​

•🌰2.vector的基本特性

🔥动态大小

vector的大小可以在运行时改变,可以存储的元素数量没有固定限制(除了系统可用内存的限制)。

🔥连续存储

vector中的元素在内存中连续存储,这使得通过迭代器指针进行遍历非常高效,同时也支持快速的随机访问。

🔥自动内存管理

当vector的大小增加时,它会自动分配新的内存空间并复制(或移动)旧元素到新空间。当vector被销毁或元素被移除时,它也会自动释放占用的内存。

 ​​​​​​

•🌰3.常用接口介绍

🔥vector对象的常见构造:

(constructor) 构造函数声明
接口说明
vector() (重点)
无参构造
vector size_type n, const value_type& val = value_type())
构造并初始化 n val
vector (const vector& x); (重点)
拷贝构造
vector (InputIterator first, InputIterator last);
使用迭代器进行初始化构造

🔥vector iterator 的使用:

iterator 的使
接口说明
begin +
end (重点)
获取第一个数据位置的 iterator/const_iterator ,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin +
rend
获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置的reverse_iterator

🔥vector 空间增长问题:
容量空间
接口说明
size
获取数据个数
capacity
获取容量大小
empty
判断是否为空
resize (重点)
改变 vector size
reserve (重点)
改变 vector capacity

【capacity】的代码在vs和g++下分别运行会发现,vs下【capacity】是按1.5倍增长的,g++是按2倍增长的这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

【reserve】只负责开辟空间,如果确定知道需要用多少空间,【reserve】可以缓解vector增容的代价缺陷问题。【resize】在开空间的同时还会进行初始化,影响【size】。

 ​​​​​​

🍋知识点二:vector常用接口

•🌰1.默认成员函数

🔥构造函数(⭐)

接口如下,前面也有,大家再仔细看看:

在文档中我们可以查看它们的具体用法: 

我们大家也需要学会查看英文文档,有不懂的就去查,锻炼我们查看英文文章的能力。 

代码示例如下:

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

void test_vector1()
{
	vector<int> v1;
	vector<int> v2(10, 1);

    vector<int> v3{ 1,2,3,4,5 };

	vector<int> v3(v2.begin(), v2.end());
	vector<int> v4(++v2.begin(), --v2.end());
}

以上这些就是常规操作。那如果我们要遍历它呢?和string一样,有三种方式:

1. 利用【size】和for循环

void test_vector1()
{
	vector<int> v1(10, 1);
	vector<int> v2(v1);

	for (size_t i = 0; i < v2.size(); i++)
	{
		cout << v2[i] << endl;
	}
	cout << endl;
}

2. 利用迭代器

void test_vector1()
{
    //while循环
	/*vector<int>::iterator it = v2.begin();
	while (it != v2.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;*/

    //for循环
	for (vector<int>::iterator it = v2.begin(); it < v2.end(); ++it)
	{
		cout << *it << " ";
	}
	cout << endl;
}

3. 利用范围for 

void test_vector1()
{
	vector<int> v1(10, 1);
	vector<int> v2(v1);

	for (auto& e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
}

 ​​​​​

🔥析构函数

析构函数直接用编译器默认生成、调用的就可以了,非常简单~

•🌰2.vector对象的访问和遍历操作

​​​​​

🔥operator[](⭐)、at

【operator[]】是一个非常重要的成员操作符,它允许你通过索引(位置)来访问vector中的元素。这个操作符提供了非常直接的元素访问方式,类似于访问普通数组的方式。

void test_vector5()
{
	vector<int> vec = { 10, 20, 30, 40, 50 };

	//访问元素  
	cout << "The first element is: " << vec[0] << endl;

	//修改元素  
	vec[1] = 25;

	//再次访问以验证修改  
	cout << "The second element is now: " << vec[1] << endl;
}

【at】成员函数是另一个用于通过索引访问元素的方法,它与【operator[]】在功能上相似,但在处理索引越界的情况时存在显著差异。 

#include <stdexcept> //为了能够抛出out_of_range异常  

void test_vector6()
{
	vector<int> vec = { 10, 20, 30 };

	try {
		//使用at,如果索引越界,将抛出异常  
		cout << "Element at index 2: " << vec.at(2) << endl;
		//下面的代码将抛出异常,因为索引3超出了vec的当前大小  
		cout << "Element at index 3: " << vec.at(3) << endl;
	}
	catch (const out_of_range& e) {
		cerr << "Caught an out_of_range exception: " << e.what() << endl;
	}

	// 使用operator[],索引越界时行为未定义  
	cout << "Element at index 2 (using operator[]): " << vec[2] << endl;
	// 下面的代码行为未定义,可能导致程序崩溃  
	// cout << "Element at index 3 (using operator[]): " << vec[3] << endl;  
}

【at】和【operator[]】的区别

  1. 异常处理
    • 在索引越界时会抛出【std::out_of_range】异常
    • 【operator[]】不进行边界检查,索引越界时行为是未定义的(Undefined Behavior, UB),可能导致程序崩溃或其他不可预测的行为。
  2. 性能
    • 由于【at】需要进行边界检查,因此在性能上通常会比不进行边界检查的【operator[]】稍慢一些。然而,这种性能差异通常非常小,除非在极端情况下(例如,在性能敏感的内层循环中频繁访问元素时)。
  3. 使用场景
    • 【at】:当你需要确保索引有效,且希望在索引无效时得到明确的错误指示时,使用at更为合适。
    • 【operator[]】:当你确信索引在有效范围内,或者即使索引越界也愿意接受未定义行为(例如,在性能非常关键且索引绝对不会越界的场合)时,使用【operator[]】可以获得更好的性能。

🔥front、back、data

【front】成员函数返回对【vector】中第一个元素的引用。如果vector为空,则调用【front】是未定义行为(即,可能会导致程序崩溃或产生不可预测的结果)。因此,在使用【front】之前,通常应检查vector是否为空,以避免潜在的错误。

 【front】使用示例:

void test_vector8()
{
	vector<int> vec = { 1, 2, 3, 4, 5 };
	if (!vec.empty()) 
	{
		int firstElement = vec.front();//获取第一个元素  
		cout << "The first element is: " << firstElement << endl;
		vec.front() = 10;//修改第一个元素  
		cout << "After modification, the first element is:
             " << vec.front() << std::endl;
	}
}

与 【front】类似,【back】成员函数返回对vector中最后一个元素的引用。同样,如果vector为空,则调用【back】也是未定义行为。

【back】使用示例:

void test_vector8()
{
	vector<int> vec = { 1, 2, 3, 4, 5 };
	if (!vec.empty())
    {
		int lastElement = vec.back();//获取最后一个元素  
		cout << "The last element is: " << lastElement << endl;
		vec.back() = 10;//修改最后一个元素  
		cout << "After modification, the last element is:
             " << vec.back() << endl;
	}
}

 【data】成员函数提供了一个指向vector内部数组第一个元素的指针。这个指针的类型是T*,其中T是vector存储的元素的类型。通过这个指针,你可以直接访问vector中的元素,就像它们是一个普通的C风格数组一样。

但是,虽然【data】返回的指针允许你以数组的方式访问vector的元素,但它并不管理内存或vector的大小。不能通过【data】返回的指针来添加或删除元素(即,你不能通过指针操作来改变vector的大小),因为这样做可能会破坏vector的内部结构或导致未定义行为。但是,你可以通过这个指针来读取或修改vector中已存在的元素。 

如果vector为空,则【data】返回的指针的值是未定义的,通常是一个空指针(但这不是C++标准要求的,只是许多实现的一种常见做法)。因此,在使用【data】返回的指针之前,最好先检查vector是否为空。

【data】使用示例:

void test_vector9()
{
	vector<int> vec = { 1, 2, 3, 4, 5 };
	if (!vec.empty()) 
	{
		//使用data()返回的指针访问vector中的元素  
		int* ptr = vec.data();
		for (int i = 0; i < vec.size(); ++i) 
		{
			cout << ptr[i] << " ";
		}
		cout << endl;

		//修改第一个元素  
		*ptr = 10;

		//使用vector的front()来验证修改  
		cout << "After modification, the first element is: "
			<< vec.front() << endl;
	}
}
🔥迭代器(⭐)

C++中的迭代器(Iterator)是一种允许你访问容器中元素的对象,而无需暴露容器的内部结构。迭代器提供了一种统一的方法来遍历容器中的所有元素,无论容器的具体类型如何(如数组、向量vector列表list等)。通过使用迭代器,你可以读取、写入或删除容器中的元素,而无需关心容器的具体实现细节。

iterator 的使
接口说明
begin +
end (重点)
获取第一个数据位置的 iterator/const_iterator ,获取最后一个数据的下一个位置的iterator/const_iterator
rbegin +
rend
获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置的reverse_iterator

 ​​​​​

•🌰3.vector对象的容量操作

在C++中,vector是一个非常灵活的容器,用于存储相同类型的元素的动态数组。关于的容量操作,主要包括以下几个方面:

或如下: 

容量空间
接口说明
size
获取数据个数
capacity
获取容量大小
empty
判断是否为空
resize (重点)
改变 vector size
reserve (重点)
改变 vector capacity

🔥size、capacity

【size】可以返回容器中元素的数量。注意,这与容量不同,它返回的是当前存储在vector中的元素个数

而【capacity】可以返回容器当前分配的存储空间能够容纳的元素数量。这个数量通常大于或等于【size】,因为vector为了效率考虑,在添加新元素时可能会分配比请求更多的空间。

我们可以通过下面的代码来观察vector对象的扩容倍数:

void test_vector2()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "capacity: " << sz << '\n';
	cout << "making v grow:\n";
	for (size_t i = 0; i < 100; i++)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

结果如下: 

 可以发现:vs下【capacity】是按1.5倍增长的。但是注意,g++是按2倍增长的这个问题经常会考察,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。

 ​​​​​

🔥reserve(⭐)

我们现在知道了顺序表的扩容,那有没有什么办法能减少扩容的次数呢?答案是有的,reserve就可以解决这个问题。

【reserve】是用来请求容器改变其容量(即它能够存储的元素数量)当你调用【reserve】时,你告诉vector它至少需要能够存储n个元素的空间。如果当前的容量小于n,则vector会重新分配其内部存储空间,以便至少能够存储n个元素。

 我们如果预留100的空间:

void test_vector2()
{
	size_t sz;
	vector<int> v;
    //预留100的空间
	v.reserve(100);
	sz = v.capacity();
	cout << "capacity: " << sz << '\n';
	cout << "making v grow:\n";
	for (size_t i = 0; i < 200; i++)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

那么就可以减少一定量的扩容:

 同时,我们要注意string类中的【reserve】和vector中的【reserve】是有区别的:

string类【reserve】测试:

void test_string8()
{
	string s("hello world and merry christmas!");
	cout << s.size() << endl;
	cout << s.capacity() << endl << endl;;

	//n < s.size() 不会缩容
	s.reserve(20);
	cout << s.size() << endl;//32
	cout << s.capacity() << endl << endl;//47

	//s.size() < n < s.capacity() 不会缩容
	s.reserve(35);
	cout << s.size() << endl;//32
	cout << s.capacity() << endl << endl;//47

	//n > s.capacity() 增容
	s.reserve(60);
	cout << s.size() << endl;//32
	cout << s.capacity() << endl << endl;//70
}

 vector【reserve】测试:

void test_vector3()
{
	vector<int> v(10, 1);
	v.reserve(20);
	cout << v.size() << endl;//10
	cout << v.capacity() << endl << endl;//20

	v.reserve(15);
	cout << v.size() << endl;//10
	cout << v.capacity() << endl << endl;//20

	v.reserve(5);
	cout << v.size() << endl;//10
	cout << v.capacity() << endl << endl;//20
}

 ​​​​​

🔥resize(⭐)

【resize】成员函数是vector提供的一个非常有用的功能,它允许你改变vector的大小,同时可以控制新增加的元素如何被初始化

【resize】示例如下:

void print_vector_element(vector<int>& v)
{
	for (auto& e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

void test_vector4()
{
	vector<int> v1(10, 2);
	cout << v1.size() << endl;//10
	cout << v1.capacity() << endl;//10

	print_vector_element(v1);
	
	v1.resize(5);
	cout << v1.size() << endl;//5
	cout << v1.capacity() << endl;//10

	print_vector_element(v1);

	v1.resize(25);
	cout << v1.size() << endl;//25
	cout << v1.capacity() << endl;//25

	print_vector_element(v1);
}

 ​​​​​

🔥clear

这里的【clear】和string中的完全类似,用于移除容器中的所有元素,使容器的大小变为0。调用【clear】后,vector仍然保留其已分配的容量(即,它内部用于存储元素的内存量可能并未减少),但所有元素都被销毁,并且容器变为空。如果之后再次向vector中添加元素,并且元素数量没有超过当前的容量,那么通常不需要重新分配内存。

 【clear】使用示例:

void test_vector13()
{
	vector<int> myvector;
	myvector.push_back(100);
	myvector.push_back(200);
	myvector.push_back(300);

	cout << "myvector contains:";
	for (unsigned i = 0; i < myvector.size(); i++)
	{
		cout << ' ' << myvector[i];//100 200 300
	}
	cout << '\n';

	myvector.clear();
	myvector.push_back(1101);
	myvector.push_back(2202);

	cout << "myvector contains:";
	for (unsigned i = 0; i < myvector.size(); i++)
	{
		cout << ' ' << myvector[i];//1101 2202
	}
	cout << '\n';
}

 ​​​​​

•🌰4.vector对象的修改操作

🔥push_back、pop_back

push_back成员函数用于在vector的末尾添加一个元素。这个元素被添加到vector的当前末尾,vector的大小随之增加1。如果添加元素导致vector的当前容量不足以存储所有元素,则vector会自动重新分配其内部存储空间以容纳更多的元素。

【push_back】使用示例:

void test_vector10()
{
	vector<int> vec;

	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);

	for (int& num : vec) 
	{
		cout << num << " ";
	}
	cout << endl;
}

 与push_back相对,pop_back成员函数用于移除vector的最后一个元素。调用【pop_back】后,vector的大小减少1,但vector的容量(即其内部存储空间的大小)可能保持不变。只有当vector为空时,调用pop_back才是未定义行为。

 【pop_back】使用示例:

void test_vector10()
{
	vector<int> vec = { 1, 2, 3, 4, 5 };

	vec.pop_back();//移除最后一个元素  

	for (int& num : vec) 
	{
		cout << num << " ";
	}
	cout << endl;
}

​​​​​

🔥insert(⭐)

【insert】成员函数用于在容器的指定位置插入一个或多个元素。这个函数非常灵活,因为它允许你在vector的任何位置插入新元素,而不仅仅是末尾。然而,需要注意的是,插入操作可能会导致vector重新分配其内部存储空间(如果当前容量不足以容纳更多元素),这可能会影响性能。

注意:【insert】在这里只支持迭代器而不支持下标作为参数了。

【insert】使用示例:

void test_vector11()
{
	vector<int> vec(10, 1);
	vec.push_back(2);
	vec.insert(vec.begin() + 3, 20);//在第三个位置之前插入20
	
	for (auto& e : vec)
	{
		cout << e << " ";
	}
	cout << endl;
}

【insert】中的迭代器失效问题:

我们先来看看【insert】的模拟实现:

iterator insert(iterator pos, const T& x)
{
	assert(pos >= _start && pos <= _finish);
	size_t length = pos - _start;
	//扩容
	if (_finish == _end_of_storage)
	{
		reserve(capacity() == 0 ? 4 : 2 * capacity());
		pos = _start + length;
	}
	iterator end = _finish - 1;
	while(end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;
	return pos;
}

大家可能会比较疑惑,为什么【insert】要返回pos,而不是之间void无返回值呢?就是为了避免迭代器pos失效的问题。

因为如果空间不够从而进行扩容,pos需要重新计算,因为内存已经被重新分配。但这里有一个问题,pos是原始迭代器,它是一个指向旧内存位置的指针或引用。及时我们再【insert】中更新了pos,但是这是形参pos,而外面的实参pos依然没有改变。从而如果我们不更新迭代器,这个迭代器将无法继续使用,即“迭代器失效”。所以,我们需要返回当前的迭代器,从而能在调用【insert】的地方改变外面的pos,如下:

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

		print_Container(v);

		size_t x = 0;
		cin >> x;
		auto* pos = find(v.begin(), v.end(), x);
		if (pos != v.end())
		{
			//insert之后pos失效,不要直接访问,要访问就要更新这个失效的迭代器
			pos = v.insert(pos, 50);
			//若未更新,则迭代器pos已失效
			*(pos + 1) *= 10;
		}

		print_Container(v);
	}

 ​​​​​

🔥erase

【erase】成员函数用于删除容器中的元素,可以从指定位置开始删除一个或多个元素。

【erase】成员函数有几种不同的重载形式,但最常用的两种形式如下:

iterator erase(iterator pos);

这个函数删除pos指向的元素,并返回一个指向被删除元素之后元素的迭代器。如果pos是end()迭代器,则函数会抛出std::out_of_range异常(但注意,在 C++11 及以后版本中不会抛出std::out_of_range异常)。 

iterator erase(iterator first, iterator last);

这个函数删除从first(包括)到last(不包括)之间的所有元素,并返回一个指向last原本指向位置(即现在的新的first之后的位置)的迭代器。注意,first和last必须是有效的迭代器,且first必须小于或等于last,否则行为未定义。 

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

int main() 
{
    vector<int> vec = { 1, 2, 3, 4, 5 };
    //删除指定位置的元素  
    auto it = vec.erase(vec.begin() + 2);//删除第三个元素(值为3的元素)  
    if (it != vec.end()) 
    {
        cout << "Deleted element, next element is: " << *it << endl;
    }
    //打印剩余元素  
    for (int i : vec) 
    {
        cout << i << " ";
    }
    cout << endl;
    //删除指定范围内的元素  
    vec.erase(vec.begin(), vec.begin() + 2);//删除前两个元素  

    //再次打印剩余元素  
    for (int i : vec) 
    {
        cout << i << " ";
    }
    cout << endl;

    return 0;
}

【erase】中的迭代器失效问题:

我们先来看看【erase】的模拟实现:

iterator erase(iterator pos)
{
	assert(pos >= _start && pos < _finish);
	iterator it = pos + 1; 
	while (it != end())
	{
		*(it - 1) = *it;
		++it;
	}
	--_finish;
	return pos;
}

【erase】也有和【insert】相同的”迭代器失效”问题,主要是因为vector是一个连续存储的容器。当你从vector中删除一个元素时,为了保持容器的连续性,所有在删除点之后的元素都需要向前移动一个位置来填补被删除元素留下的空白。 

所以【erase】函数会返回一个指向被删除元素之后元素的迭代器。如果你需要在删除后继续遍历或操作容器,可以使用这个返回的迭代器作为新的起点。我们再模拟实现的时候,也需要向原码对齐。

 ​​​​​

🔥swap

【swap】成员函数用于交换两个vector容器的内容。调用【swap】之后,两个vector将包含彼此原本的元素,但它们的容量(capacity)和大小(size)也会相应地交换。【swap】操作是一个高效的操作,因为它通常只需要交换两个vector的内部指针和大小信息,而不需要移动任何元素。

 【swap】使用示例:

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

int main() 
{
    vector<int> vec1 = { 1, 2, 3 };
    vector<int> vec2 = { 4, 5, 6, 7 };

    //交换vec1和vec2的内容  
    vec1.swap(vec2);

    //输出结果,以验证swap的效果  
    for (int n : vec1) 
    {
        cout << n << ' ';
    }
    std::cout << '\n';

    for (int n : vec2) 
    {
        cout << n << ' ';
    }
    cout << '\n';

    //输出:  
    //4 5 6 7   
    //1 2 3   

    return 0;
}

 ​​​​​

🔥assign

【assign】成员函数用于给vector分配新的内容,替换其当前内容。这个函数可以接受不同种类的参数,以允许你以多种方式初始化或重新初始化vector。

【assign】成员函数有几个重载版本,但最常见的几个是:

1.分配单个值的重复

void assign(size_type n, const T& value);

这会将vector的大小设置为n,并用value的副本填充它。如果n大于当前大小,将添加新元素;如果n小于当前大小,将删除超出部分的元素。 

2.从另一个范围分配

template<class InputIt>  
void assign(InputIt first, InputIt last);

这会将vector的内容替换为来自迭代器first和last所定义范围内的元素的副本。这个范围必须是有效的,即first和last必须是可比较的,并且first不能指向last之后的元素。 

【assign】使用示例:

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

int main() 
{
    vector<int> vec;

    //使用单个值的重复分配  
    vec.assign(5, 10);
    for (int n : vec) 
    {
        cout << n << ' ';//输出: 10 10 10 10 10  
    }
    cout << '\n';

    //从另一个范围分配  
    std::vector<int> vec2 = { 1, 2, 3, 4, 5 };
    vec.assign(vec2.begin(), vec2.end());
    for (int n : vec) 
    {
        cout << n << ' ';//输出: 1 2 3 4 5  
    }
    cout << '\n';

    //从初始化列表分配(C++11及以后)  
    vec.assign({ 6, 7, 8, 9, 10 });
    for (int n : vec) 
    {
        cout << n << ' ';//输出: 6 7 8 9 10  
    }
    cout << '\n';

    return 0;
}

•🌰5.vector的非成员函数

🔥relational operators

vector中也提供了类似string的【relational operators】:

使用示例:

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

int main()
{
	vector<int> foo(3, 100);   
	vector<int> bar(2, 200);   

	if (foo == bar) cout << "foo and bar are equal\n";
	if (foo != bar) cout << "foo and bar are not equal\n";
	if (foo < bar) cout << "foo is less than bar\n";
	if (foo > bar) cout << "foo is greater than bar\n";
	if (foo <= bar) cout << "foo is less than or equal to bar\n";
	if (foo >= bar) cout << "foo is greater than or equal to bar\n";

	return 0;
}

 

•🌰6.vector模拟二维数组

🔥模拟实现二维数组

我们可以利用vector模拟二维数组:

void test_vector1()
{
	vector<int> v(5, 1);
	//vector中有10个vector<int>类型的变量,每个这样的变量都是一个一维数组
	vector<vector<int>> vv(10, v);
	//修改第二行第二列的元素
	vv[2][1] = 2;
	//上述代码等价于
	vv.operator[](2).operator[](1) = 2;
}

图解如下:

那么如何遍历这个二维数组呢?

for (size_t i = 0; i < vv.size(); i++)
{
	for (size_t j = 0; j < vv[i].size(); j++)
	{
		cout << vv[i][j] << " ";
	}
	cout << endl;
}
cout << endl;

上述两个for循环即可,注意控制条件。

🔥杨辉三角

题目:给定一个非负整数numRows生成「杨辉三角」的前numRows 行。

代码如下:

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv(numRows);
        for(size_t i = 0; i < numRows; i++)
        {
            vv[i].resize(i + 1, 0);
            vv[i].front() = vv[i].back() = 1;
        }
        for(size_t i = 2; i < vv.size(); i++)
        {
            for(size_t j = 1; j < vv[i].size() - 1; j++)
            {
                vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];
            }
        }
        return vv;
    }
};

 

•🌰7.vector在OJ中的使用

如果大家对vector的模拟实现感兴趣,可以参考:vector模拟实现+测试代码

以下是vector在OJ中的应用:

136. 只出现一次的数字 - 力扣(LeetCode)

118. 杨辉三角 - 力扣(LeetCode)

26. 删除有序数组中的重复项 - 力扣(LeetCode)

137. 只出现一次的数字 II - 力扣(LeetCode)

260. 只出现一次的数字 III - 力扣(LeetCode)

数组中出现次数超过一半的数字_牛客题霸_牛客网 (nowcoder.com)

17. 电话号码的字母组合 - 力扣(LeetCode)

 • ✨SumUp结语

到这里本篇文章的内容就结束了,本节介绍了C++中vector的相关知识。这里的内容非常多,非常丰富,下一篇章我们进入ist的学习。望大家能够认真学习,打好基础,迎接接下来的挑战,期待大家继续捧场~💖💖💖

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值