目录
(2) C++里面对victor初始化的时候传参数代表的是将这个victor预先扩容,扩容成指定数字的大小。
(3)如果vector想尾插数据,开空间用reserve还是resize?——用reserve
(4)string vector等都有一个特点,删除数据,一般是不会主动缩容
(4)vector中没有find函数,要用算法中的find函数
5.std::vector::iterator 没有重载 >>运算符
三.std::vector::at 和 std::vector::operator[] 都会去做边界检查
一.vector的定义
定义:可以动态增长的数组
1.vector构造函数
![](https://i-blog.csdnimg.cn/blog_migrate/9b68f26c5a77fe9a63f6013706f4e9d6.png)
size_type 就是被typedef的size_t
![](https://i-blog.csdnimg.cn/blog_migrate/eb75004e3094d3dc765d8fb36a1966b6.png)
#include<vector>
#include<iostream>
using namespace std;
void test_vector1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<double> v2;
v2.push_back(1.1);
v2.push_back(2.2);
v2.push_back(3.3);
vector<string> v3;
v3.push_back("李白"); //单参数的构造函数支持隐式类型转换:
v3.push_back("杜甫"); //string s="hello world";先构造再拷贝构造
v3.push_back("苏轼");
v3.push_back("白居易");
vector<int> v4(10, 5);
vector<string> v5(++v3.begin(), --v3.end()); //迭代器,此处是"杜甫","苏轼"
string s = "hello world";
vector<char> v6(s.begin(), s.end());
}
(2) C++里面对victor初始化的时候传参数代表的是将这个victor预先扩容,扩容成指定数字的大小。
2.vector遍历
与string遍历大致相同
void test_vector2()
{
// 遍历
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// 1、下表+[]
for (size_t i = 0; i < v.size(); ++i)
{
v[i] += 1;
cout << v[i] << " ";
}
cout << endl;
// 2.迭代器
vector<int>::iterator it = v.begin();
while (it != v.end())
{
*it -= 1;
cout << *it << " ";
++it;
}
cout << endl;
// 3.范围for
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
3.vector的增容
(1)两种版本下的扩容
vs下面-- PJ版本——1. 5倍增容
linux g++ SGI版本——2倍增容
(2)单次增容增多少的问题分析:(不用考虑内存对齐)
即为什么vs下扩容按1.5倍扩容,linux的g++扩容按2倍扩容?
单次增容越多,插入N个值,增容次数越少,效率就越高,但是浪费空间就越多;
单次增容越少,浪费空间就少了,但是会导致频繁增容,效率低下。
因此不一定是1.5倍或者2倍,也可能是3,4倍,只是1.5或2倍是一个比较平衡的值。
(3)如果vector想尾插数据,开空间用reserve还是resize?——用reserve
如果知道要开多大空间且后续要进行尾插,就用reserve提前开好。
如果用resize就是开空间并初始化,比如foo.resize(100); 开100个int空间,全部初始化成0,如果再foo.push_back(i); 就是在这100个空间以后再加数据,因为前100个已经有数据了
void test_vector3()
{
//vector<char> v;
//cout << v.max_size() << endl;
size_t sz;
std::vector<int> foo;
foo.reserve(100); //如果知道要开多大空间,就用reserve提前开好
//foo.resize(100);
sz = foo.capacity();
std::cout << "making foo grow:\n";
for (int i = 0; i < 100; ++i) {
foo.push_back(i);
if (sz != foo.capacity()) {
sz = foo.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
}
(4)string vector等都有一个特点,删除数据,一般是不会主动缩容
若非要缩容,那就用函数 shrink_to_fit() ,但是要慎用,少用,表面是缩容_capacity——>_size,实际它的底层是开辟一块_size的空间,并把内容拷贝过来,实际上是用时间换空间了,但是我们一般是不差空间的,而且通常是用空间换时间,所以说不建议时间换空间的做法,即:少用 shrink_to_fit() 函数。
void test_vector3()
{
//vector<char> v;
//cout << v.max_size() << endl;
size_t sz;
std::vector<int> foo;
foo.reserve(100);
//foo.resize(100);
sz = foo.capacity();
std::cout << "making foo grow:\n";
for (int i = 0; i < 100; ++i) {
foo.push_back(i);
if (sz != foo.capacity()) {
sz = foo.capacity();
std::cout << "capacity changed: " << sz << '\n';
}
}
//vector<int> countV;
//countV.resize(100, 1);
//countV.resize(10);
// string vector等都有一个特点,删除数据,一般是不会主动缩容
foo.resize(10);
cout << foo.size() << endl;
cout << foo.capacity() << endl;
// 慎用、少用
foo.shrink_to_fit();
cout << foo.size() << endl;
cout << foo.capacity() << endl;
}
4.vector的几个常用函数
(1)insert,erase
他们都是不支持下标增加或删除的,都是用的迭代器
返回值是iterator是为了解决迭代器失效,这个后面再详细说。
void test_vector4()
{
// 遍历
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.insert(v.begin(), -1);
v.insert(v.begin(), -2);
v.insert(v.begin(), -3);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.insert(v.begin()+7, 300);
//v.insert(v.begin()+8, 300);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.erase(v.begin());
v.erase(v.begin());
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
(2)swap
交换两个vector类对象指向的空间,例如:v1.swap(v2);
void test_vector4()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int> v2;
v2.push_back(5);
v2.push_back(5);
v2.push_back(5);
v2.push_back(5);
v1.swap(v2);
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;
}
(3)clear
清掉全部数据
(4)vector中没有find函数,要用算法中的find函数
algorithm——算法 #include<algorithm>
void test_vector5()
{
// 遍历
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//vector<int>::iterator pos = find(v.begin(), v.end(), 3);
auto pos = find(v.begin(), v.end(), 3); //类型太长可以用auto
if (pos != v.end())
{
cout << "找到了" << endl;
v.erase(pos);
}
else
{
cout << "没有找到" << endl;
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
(5)算法中的排序 sort
#include<algorithm>
sort默认是升序
void test_vector5()
{
// 遍历
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(0);
v.push_back(9);
v.push_back(3);
v.push_back(1);
// 默认是升序
sort(v.begin(), v.end()); // <
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
排降序,仿函数
关于仿函数,大家先记住这个用法,具体我们后面讲队列再详细讲
void test_vector5()
{
// 遍历
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(0);
v.push_back(9);
v.push_back(3);
v.push_back(1);
// 默认是升序
//sort(v.begin(), v.end()); // <
// 排降序,仿函数
// 关于仿函数,大家先记住这个用法,具体我们后面讲队列再详细讲
// sort(v.begin(), v.end(), greater<int>()); // >
greater<int> g;
sort(v.begin(), v.end(), g); // >
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
5.std::vector::iterator 没有重载 >>运算符
vector底层是以当前类型的指针作为迭代器,对于指针而言,能够进行操作的方法都支持,如==,++,*,而>>运算符并没有重载。
二.vector相关题目
1.题目:杨辉三角
给定一个非负整数 numRows
,生成「杨辉三角」的前 numRows
行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
示例 1:
输入: numRows = 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1 输出: [[1]]
思路:
解法1:
c语言解法:
2.26. 删除有序数组中的重复项
用双指针法
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int fast=1,slow=1,n=nums.size();
while(fast<n)
{
if(nums[fast]!=nums[fast-1])
{
nums[slow]=nums[fast];
slow++;
}
fast++;
}
return slow;
}
};
3.137. 只出现一次的数字 II
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
for(int i=0;i<32;i++)
{
int total=0;
for(int num:nums)
{
total+=(num>>i)&1;
}
if(total%3) // ans|=((total%3)<<i);也行
ans|=(1<<i);
}
return ans;
}
};
4.260. 只出现一次的数字 III
用ret记录所以数异或的结果,找到ret二进制位是1的最低的那一位,因为是异或,相异为1,出现过两次的数异或都是0,只有出现过一次的这两个数,他们总有一位二进制位不同,即:一个是1,一个是0,异或以后就是1,所以这一位一定有一个数是0,一个数是1。通过把这一位分成a,b两组,每组分别异或起来的结果a,b就是这两个出现过一次的数。
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int ret=0; //所有数字异或的结果
int i=0;
int h=1;
int a=0;
int b=0;
vector<int> v;
for(int e:nums)
{
ret^=e; //所有数字异或起来
}
while((ret&h)==0)
{
h<<=1;
i++; //找到异或结果是1的那一位,因为是异或,所以这一位一定有一个数是0,一个数是1
}
for(int e:nums)
{
if((e>>i)&1)
{
a^=e;
}
else
{
b^=e;
}
}
v.push_back(a);
v.push_back(b);
return v;
}
};
5.17. 电话号码的字母组合
自己手敲的:
class Solution {
string _numToStr[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:
void _letterCombine(string digits,int di,string combineStr,vector<string>& retV)
{
if(di==digits.size())
{
retV.push_back(combineStr);//vector没有+=
return;
}
int num=digits[di]-'0';//取到数字字符转换成数字,再取到映射的字符串
for(char ch:_numToStr[num])
{
_letterCombine(digits,di+1,combineStr+ch,retV);
}
}
vector<string> letterCombinations(string digits) {
string str;
int i=0;
vector<string> retV;
if(digits=="")
{
return retV;
}
_letterCombine(digits,i,str,retV);
return retV;
}
};
6.JZ42 连续子数组的最大和
做法:dp表示此坐标对应的array数据包含array[i]后的最大连续数据,maxsum表示最大连续数据。例如前四个1 -2 3 10,dp[0]和maxsum都存1。i=1时,dp[1]比较连续数据 -2(array[i]) 和 1-2=-1 (dp[i-1]+array[i]) 谁大存谁,存 -1,此时maxsum(最大连续数据)还是1不变;dp[2]比较连续数据 3 和 3-1=2 (3加上包含前一个值的最大连续数据,即 array[i]+dp[i-1] ) ,存3,此时maxsum由1更新为2;dp[3]比较连续数据 10 和 10+3=13 (3加上前面的连续数据) ,存13,此时maxsum由2更新为13;依次类推。
class Solution {
public:
int FindGreatestSumOfSubArray(vector<int> array) {
vector<int> dp(array.size(),0);
dp[0]=array[0];
int maxsum=dp[0];
for(int i=1;i<array.size();i++)
{
dp[i]=max(array[i]+dp[i-1],array[i]);
maxsum=max(maxsum,dp[i]);
}
return maxsum;
}
};
三.std::vector::at 和 std::vector::operator[] 都会去做边界检查
at() 函数和 [] 运算符的重载,两者都可以得到相应下标的值,并且两者都会去做边界检查。
当发生越界行为时,at 是抛异常,operator[] 是报出 assert 错误