C++ vector

目录

遍历

operator[ ]

迭代器

范围for

 课习题(1)

vector扩容

reserve和resize

插入

(1)在头部头插一个0:

(2)在指定数值前插入一个值

清理

课习题2

vector的模拟实现


国庆放假第二天,奥利给,继续干。

看一下vector的构造函数:

 (1)默认构造函数:

vector <int> s1();

(2)复制初始化构造:

	vector <int> s2(10, 3);

(3)范围区间构造:

甚至可以用string的begin,end:

	string v1("hello");
	vector <int> s3(v1.begin(), v1.end());

遍历

operator[ ]

利用下标实现遍历:

	
	string v1("hello");


    for (size_t i = 0; i < v1.size(); i++)
	{
		
		cout << v1[i] << " ";

		
	}
	cout << endl;

迭代器



	string v1("hello");
	vector <int> s3(v1.begin(), v1.end());


	vector<int>::iterator it = s3.begin(); 
	while (it != s3.end()) {
		cout << *it << " ";
		it++;
	}
	cout << endl;

 因为是<int>,所以输出的是“hello”的ASCII码值:

如果把vector的模版类型改为char的话输出的就是“hello”:

范围for


	string v1("hello");
	vector <int> s3(v1.begin(), v1.end());

	for (auto h1 : s3)
	{
		cout << h1 << " ";
	}
	cout << endl;

 课习题(1)

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

解析:

vector扩容

扩容要用的函数参考:

如下代码:

	vector<int> s1;
	auto sz = s1.capacity();
	for (size_t i = 0; i < 100; i++)
	{
		s1.push_back(i);
		
		if (sz != s1.capacity())
		{
			sz = s1.capacity();
		cout << "扩容:" << s1.capacity() << endl;
		}
	}

if (sz != s1.capacity())
        {
            sz = s1.capacity();
    
        }    

这个if语句的作用是什么呢?

如果删掉if语句运行:

 它会没执行一次循环就扩容一次,最后扩容一百次,if语句的作用就是限制了扩容,让它只有在空间不够的条件下菜扩容。

观察扩容的数字规律:发现它是一次扩容1.5的(受内存对齐影响看起来不完全是1.5倍扩容)。

我们看g++下的扩容规律:

我们发现它是二倍扩容的关系。

reserve和resize

同样一段代码,用reserve和resize的运行结果区别:

	vector<int> s1;
	auto sz = s1.capacity();
	//s1.reserve(100);
	//s1.resize(100);
	cout << "开空间:" << s1.capacity() << endl;
	for (size_t i = 0; i < 100; i++)
	{
        s1[i]=i;
		
		if (sz != s1.capacity())
		{
			sz = s1.capacity();
cout << "扩容:" << s1.capacity() << endl;
		}		

 reserve:

resize:

 因为reserve只是提前开空间,开的空间够用了就不再扩容了,它不会往里面写值。

但是resize是size和capacity都扩到了100,并且会实际往里面写入值,写100个int需要400个字节,所以还需要接着扩容。

用reserve开辟100个空间,然后遍历一下,打印出来:




	vector<int> s1;
	auto sz = s1.capacity();
	s1.reserve(100);
	//s1.resize(100);
	cout << "开空间:" << s1.capacity() << endl;
	for (size_t i = 0; i <s1.size(); i++)
	{
		s1[i]=i;
	}
	for (auto ch : s1)
	{
		cout << ch << endl;
   }

 这是因为reserve只把capacity开辟了100个空间,但是size还是0:

那么强行写入呢?既然空间已经开出来了,那直接往里面写入会怎么样:



	vector<int> s1;
	auto sz = s1.capacity();
	s1.reserve(100);
	//s1.resize(100);
	cout << "开空间:" << s1.capacity() << endl;
	for (size_t i = 0; i <100; i++)
	{
		s1[i]=i;
	}
	for (auto ch : s1)
	{
		cout << ch << endl;
   }

 会报异常:

这是因为方括号里面有断言:

 如果就是想访问呢,解决办法:

(1)用resize,把size也开成100,这样就不会越界了:

	vector<int> s1;
	auto sz = s1.capacity();
	//s1.reserve(100);
	s1.resize(100);
	cout << "开空间:" << s1.capacity() << endl;
	for (size_t i = 0; i <100; i++)
	{
		s1[i]=i;
	}
	for (auto ch : s1)
	{
		cout << ch << " ";
   }
	cout << endl;

(2)不用下标访问就不会越界,用push_back:


	vector<int> s1;
	auto sz = s1.capacity();
	s1.reserve(100);
	//s1.resize(100);
	cout << "开空间:" << s1.capacity() << endl;
	for (size_t i = 0; i <100; i++)
	{
		s1.push_back(i);
	}
	for (auto ch : s1)
	{
		cout << ch << " ";
   }

插入

vector不支持流插入,流提取,也就是我们直接把值打印出来:

这是因为vector是一个顺序表,如果直接把值打印出来编译器不明白是什么意思,假如你插入1,2,3,4

直接打印出来就是:

1234

 那编译器会认为这是整数1234还是12 ,34还是123,4还是1,2,34……

那么为什么string可以直接输出呢?

 string有直接流提取流输出的需求,列如输入"hello world",直接输出"hello world",就是我们想要的效果了,编译器不存在看不懂的情况。

解决方法,先遍历一遍,把我们需要分别的地方分别好再输出(列如数字之间的空格):


	vector<int> s1;

	s1.push_back(1);
	s1.push_back(2);
	s1.push_back(3);
	s1.push_back(4);

	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;

要用到的函数参考:

(1)在头部头插一个0:

可以用insert:

pos我们可以用迭代器里的begin就可以找到头部了:

	vector<int> s1;

	s1.push_back(1);
	s1.push_back(2);
	s1.push_back(3);
	s1.push_back(4);

	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;
	s1.insert(s1.begin(), 0);
	for (auto ch : s1)
	{
		cout << ch << " ";
	}
	cout << endl;

(2)在指定数值前插入一个值

vector没有写find,但是在算法里面有find,这个find在标准库里,是一个模版,大家都可以用,如下:

 我们可以通过find找到值为3的数字,再通过inser()在3前插入一个30:


auto it=find(s1.begin(),s1.end(),3);
 
 if (it != s1.end())
 {
	 s1.insert(it, 30);
 }

 for (auto ch : s1)
 {
	 cout << ch << " ";
 }
 cout << endl;

删除一个指定的数:

先通过find找到这个数,然后再通过eraser删除这个数:

 auto it1 = find(s1.begin(), s1.end(), 30);

 if (it1 != s1.end())
 {
	 s1.erase(it1);
 }

 for (auto ch : s1)
 {
	 cout << ch << " ";
 }
 cout << endl;

清理

可以用clean来释放size,但是clean只能释放size不能释放空间(capacity):

s1.clean();

要想手动释放空间不能通过调用析构函数来释放,因为析构函数不能被显示调用。 

 我们通过shrink_to_fit来释放空间:

 也就是先把size释放为0,然后再用hrink_to_fit会把capacity缩到和size一样大小:

 s1.shrink_to_fit();

课习题2

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

思路:

异或:

 也就是异或是符合结合律的,让这个数组内部自己慢慢异或,最后的结果一定就是那个数组中唯一的值,因为其他出现两次或三次的数都被异或为0了。

代码:

写一个循环,把这个数组遍历一下,然后让数组内部异或,把最后得出的值返回即可:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
     
    size_t val=0;

     for(size_t i=0;i<nums.size()-1;i++)
     {
      val^=nums[i];
     }
    return val;


    return val;
    }
};

但是这个代码是通过不了的,因为vector是一个顺序表,遍历它需要先存值,而存值需要开空间,所以我们需要reverse或者resize一个空间。

reverse只开辟capacity不开辟size大小无法遍历,所以我们用reszie。

案列能通过多少取决于你开多少空间和size:

 : 


上面是之前写的,有误,现在来修改一下:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
     
    size_t val=0;

     for(size_t i=0;i<nums.size()-1;i++)
     {
      val^=nums[i];
     }
    return val;


    return val;
    }
};

这个代码通不过的原因是因为i<nums.size()-1了,最后一位访问不到,所以通不过:

而加了nums.resize(10000);就是把size扩容了一下,使我们可以访问到最后一位,所以可以通过:

实际上我们只需要改为i<resize()使i可以访问到最后一位就可以了:

 因为我们并不知道需要开多大空间,只能自己慢慢试,最后还开多了。因此我们可以用范围for,范围for会自动开辟空间,自己设置条件,自己++:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
     
    size_t val=0;
//手动开空间,手动遍历:
    //  nums.resize(100000);
    //  for(size_t i=0;i<nums.size()-1;i++)
    //  {
    //   val^=nums[i];
    //  }
    // return val;

//自动开空间,自动遍历:
for(auto ch:nums)
{
    val^=ch;
}
return val;

    return val;
    }
};

课习题(3)118. 杨辉三角 - 力扣(LeetCode)

 思路:首先要知道  vector<vector<int>>啥意思。

vector<int>的意思就是一个类型为Int的顺序表。

那么  vector<vector<int>>就好理解了,无非就是多个int顺序表。

用图表示的话就是这个样子:

那么我们应该怎么去做一个杨辉三角的树呢

其实就是二维数组。

思路:

我们可以把一个顺序表看做一行,我们访问哪个vector就是访问那一行,

然后我们把一行变成0,把这一行的开头和结尾变成1:

然后我们就可以把变成0的那个位置进行操作:

让这个位置的值=上一行同一个下标列左边的值+上一行下标列-1的值。

vector的模拟实现

这个部分要结合vector的与源码来看的。

第一个版本:vector · 孙鹏宇/孙鹏宇的第一个仓库 - 码云 - 开源中国 (gitee.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙鹏宇.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值