C++:vector讲解【前序】

目录

1.vector构造函数

(2) C++里面对victor初始化的时候传参数代表的是将这个victor预先扩容,扩容成指定数字的大小。

2.vector遍历

3.vector的增容

(1)两种版本下的扩容

(2)单次增容增多少的问题分析:(不用考虑内存对齐)

(3)如果vector想尾插数据,开空间用reserve还是resize?——用reserve

(4)string vector等都有一个特点,删除数据,一般是不会主动缩容

4.vector的几个常用函数

(1)insert,erase

(2)swap

(3)clear 

(4)vector中没有find函数,要用算法中的find函数

(5)算法中的排序 sort 

5.std::vector::iterator 没有重载 >>运算符

二.vector相关题目

1.题目:杨辉三角

思路:

​编辑

解法1:

c语言解法:

2.26. 删除有序数组中的重复项

3.137. 只出现一次的数字 II

4.260. 只出现一次的数字 III

5.17. 电话号码的字母组合

6.JZ42 连续子数组的最大和

三.std::vector::at 和 std::vector::operator[] 都会去做边界检查


一.vector的定义

定义:可以动态增长的数组

1.vector构造函数

size_type 就是被typedef的size_t

#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.题目:杨辉三角

118. 杨辉三角

给定一个非负整数 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 错误

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值