1. vector简介
template<class T, class Alloc = allocator<T>>
class vector;
vector是一个可以动态增长的数组,T是要存储的元素类型。vector可以像数组一样,用下标+[]来访问元素,如:
int arr[] = {1,2,3,4};
for (int i = 0; i < 4; ++i)cout << arr[i] << " ";
cout << endl;
vector<int> v = {1,2,3,4};
for (int i = 0; i < 4; ++i)cout << v[i] << " ";
输出:
1 2 3 4
1 2 3 4
2. vector的构造函数
本文不考虑allocator的问题,尽可能简化vector的使用方式。
2.1 无参构造
explicit vector();
最常见的构造,构造一个空的vector。
vector<int> v;
2.2 n个val
explicit vector(size_t n, const T& val = T());
用n个val来初始化vector。
vector<int> v1(5); // 用5个0来初始化vector
vector<int> v2(3, 1); // 用3个1来初始化vectorfor (auto e : v1)cout << e << " ";
cout << endl;
for (auto e : v2)cout << e << " ";
输出:
0 0 0 0 0
1 1 1
由于explicit的作用,下面的写法并不是调用这个构造函数,而是initializer_list。
vector<int> v = {3,1};
2.3 拷贝构造
vector(const vector<T>& v);
用一个vector来拷贝初始化另一个vector。
vector<int> v1 = {1,2,3,4,5};
vector<int> v2(v1);
vector<int> v3 = v1; // 这里的v3调用的也是拷贝构造,等价于vector v3(v1);
for (auto e : v1) cout << e << " ";
cout << endl;
for (auto e : v2) cout << e << " ";
cout << endl;
for (auto e : v3) cout << e << " ";
输出:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
2.4 迭代器构造
template<class InputIterator>
vector(InputIterator first, InputIterator last);
用任意类型的迭代器构造。
int arr[] = {1,2,3};
vector<int> v(arr, arr + sizeof(arr)/sizeof(arr[0]));
for(auto e : v) cout << e << " ";
输出:
1 2 3
2.5 列表初始化
vector(initializer_list<T> il);
使用列表初始化。
vector<int> v1 = {1,2,3};
vector<int> v2{4,5,6};
for (auto e : v1) cout << e << " ";
cout << endl;
for (auto e : v2) cout << e << " ";
输出:
1 2 3
4 5 6
3. vector的迭代器
vector的迭代器是随机访问迭代器(random access iterator),提供begin,end,rbegin,rend等接口。
iterator begin();
const_iterator begin() const;iterator end();
const_iterator end() const;reverse_iterator rbegin();
const_reverse_iterator rbegin() const;reverse_iterator rend();
const_reverse_iterator rend() const;
举一个正向迭代器使用的例子:
vector<int> v = {1,2,3,4,5};
auto it = v.begin();
while (it != v.end)
{cout << *it << " ";++it;
}
输出:
1 2 3 4 5
上述代码和下面的代码是等价的,因为范围for的底层也是用迭代器实现的。
vector<int> v = {1,2,3,4,5};
for (auto e : v)cout << e << " ";
4. vector的容量相关接口
4.1 size
size_t size() const;
获取数据个数。
vector<int> v = {1,2,3,4,5};
cout << v.size() << endl;
输出:
5
4.2 capacity
size_t capacity() const;
获取容量大小。
vector<int> v;
for (int i = 0; i < 30; ++i) v.push_back(i);
cout << v.capacity() << endl;
VS2022的环境下输出:
42
4.3 empty
bool empty() const;
判断vector是否为空。
vector<int> v;
cout << v.empty() << endl; // true
v.push_back(1);
cout << v.empty() << endl; // false
输出:
1
0
4.4 resize
void resize(size_t n, const T& val = T());
把vector的size改为n。若n小于当前size,则只保留前n个数据;若n大于当前size,则插入val,直到size为n。
vector<int> v = {1,2,3,4};v.resize(6); // n大于当前size
for (auto e : v) cout << e << " ";
cout << endl;v.resize(2); // n小于当前size
for (auto e : v) cout << e << " ";
cout << endl;v.resize(4, 5); // n大于当前size
for (auto e : v) cout << e << " ";
输出:
1 2 3 4 0 0
1 2
1 2 5 5
4.5 reserve
void reserve(size_t n);
改变capacity,至少改为n,保留足够的空间。
vector<int> v;
v.reserve(100);
cout << v.capacity() << endl;
输出示例:
100
5. vector的增删查改
5.1 push_back和pop_back
void push_back(const T& val);
void pop_back();
尾插和尾删,push_back在vector的最后插入val,pop_back删除vector的最后一个元素。
vector<int> v = {1,2,3,4,5};
v.pop_back();
for (auto e : v) cout << e << " ";
cout << endl;
v.push_back(6);
for (auto e : v) cout << e << " ";
输出:
1 2 3 4
1 2 3 4 6
5.2 全局find + vector的迭代器
template<class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T& val);
使用algorithm中的find,配合vector的迭代器,查找[first,last)中有没有val,若找到了,返回指向val的迭代器;若没找到,返回last。
vector<int> v = {1,2,3,4,5};
auto it = find(v.begin(), v.end(), 3);
if (it != v.end()) cout << *it << endl;
else cout << "没找到" << endl;
输出:
3
5.3 insert + erase
iterator insert(iterator pos, const T& val);
iterator erase(iterator pos);
插入和删除元素。insert负责在pos位置插入val,并返回指向val的迭代器。erase负责删除pos位置的值,并返回指向删除元素的下一个元素的迭代器。
配合find,在3前面插入30,再删除所有偶数的代码如下:
vector<int> v = {6,2,3,4,5,10,12};
auto it = find(v.begin(), v.end(), 3);
if (it != v.end())
{it = v.insert(it, 30);// 此时it指向30cout << *it << endl;
}
for (auto e : v) cout << e << " ";
cout << endl;// 删除所有偶数
it = v.begin();
while (it != v.end())
{if (*it % 2 == 0) it = v.erase(it);else ++it;
}
for (auto e : v) cout << e << " ";
输出:
30
6 2 30 3 4 5 10 12
3 5
5.4 swap成员函数 + 全局函数
// 成员函数
void swap(vector<T> v);// 全局函数
template<class T>
void swap(vector<T>& v1, vector<T>& v2);
交换2个vector。
vector<int> v1 = {1,2,3,4,5};
vector<int> v2 = {6,7,8,9,0};
for (auto e : v1) cout << e << " ";
cout << endl;
for (auto e : v2) cout << e << " ";
cout << endl;v1.swap(v2);
for (auto e : v1) cout << e << " ";
cout << endl;
for (auto e : v2) cout << e << " ";
cout << endl;swap(v1, v2);
for (auto e : v1) cout << e << " ";
cout << endl;
for (auto e : v2) cout << e << " ";
输出:
1 2 3 4 5
6 7 8 9 0
6 7 8 9 0
1 2 3 4 5
1 2 3 4 5
6 7 8 9 0
5.5 operator[]
T& operator[](size_t pos);
const T& operator[](size_t pos) const;
像数组一样,使用下标+[]访问vector。
vector<int> v = {1,2,3,4,5};
for (size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";
输出:
1 2 3 4 5
6. 迭代器失效问题
6.1 场景1:插入 + 扩容
所有的插入操作都有可能导致扩容,从而导致迭代器失效,如resize、reserve、insert、assign、push_back等。这是因为,扩容的步骤是:
- 开辟一块新的更大的空间。
- 把旧的空间的数据拷贝到新的空间中去。
- 释放旧的空间。
而扩容前,迭代器指向了旧的空间,扩容后,旧的空间被释放了,迭代器指向的空间已经被销毁,迭代器失效。
下面的代码中,在reserve之后,迭代器it失效,出现野指针问题。
vector<int> v = {1,2,3,4,5};
auto it = v.begin();
v.reserve(100);
while (it != v.end()) cout << *it++ << " ";
6.2 场景2:删除
删除操作,如erase,会挪动数据覆盖删除,此时迭代器指向的元素可能已经改变,甚至指向非法的空间。如:
vector<int> v = {1,2,3,4,5};
auto it1 = v.end() - 2; // 指向4
auto it2 = v.end() - 1; // 指向5v.erase(v.begin());
上面的代码中,erase之后,it1指向的元素已经不是4了(此时it1指向5),而it2指向了非法的空间。这是因为,erase的底层会覆盖删除1,会把1后面的元素向低地址处挪动1格。
erase前
1 2 3 4 5^ ^it1 it2
erase后
2 3 4 5^ ^it1 it2
6.3 解决方案
迭代器失效后,要对迭代器重新赋值。
下面的程序,本意是删除vector中所有的偶数,但是erase之后,迭代器失效了,程序的行为是未定义的。
vector<int> v = {2,4,5,6,7,8,10};
auto it = v.begin();
while (it != v.end())
{if (*it % 2 == 0)v.erase(it);++it;
}
解决方案:在erase之后,对it重新赋值。注意到erase会返回指向删除元素的下一个元素的迭代器,当找到偶数并删除后,it应该接受erase的返回值;若it指向的不是偶数,it++即可。
vector<int> v = {2,4,5,6,7,8,10};
auto it = v.begin();
while (it != v.end())
{if (*it % 2 == 0)it = v.erase(it);else++it;
}for (auto e : v) cout << e << " ";
输出:
5 7
7. 练习
7.1 只出现一次的数字I
只出现一次的数字I原题链接https://leetcode.cn/problems/single-number/description/使用范围for,取出所有数字,异或到一起。根据异或的特性,相同的数字会被抵消,最后的结果就是只出现一次的数字。
class Solution {
public:int singleNumber(vector<int>& nums) {int ret = 0;for (auto n : nums) ret ^= n;return ret;}
};
7.2 杨辉三角
杨辉三角原题链接https://leetcode.cn/problems/pascals-triangle/description/总共numRows行,每行有i+1个元素,两端的元素是1,其余元素(i,j)是(i-1,j-1)和(i-1,j)相加的结果。 遍历vv,类似于遍历二维数组,可以用下标+[],注意边界由size决定。对于vector类型,v[0]等价于v.front(),v[size()-1]等价于v.back()。
class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv(numRows); // numRows行//for (int i = 0; i < vv.size(); ++i)for (int i = 0; i < numRows; ++i){// 每行有i+1个元素vv[i].resize(i + 1);vv[i].front() = vv[i].back() = 1;//for (int j = 1; j < vv[i].size() - 1; ++j)for (int j = 1; j < i; ++j){vv[i][j] = vv[i-1][j-1] + vv[i-1][j];}}return vv;}
};
7.3 删除有序数组中的重复项
删除有序数组中的重复项原题链接https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/由于数组是有序的,考虑使用下标i遍历数组,若遇到和前一个元素不相同的元素,就存储到下标j对应的空间中。注意i和j都要从1开始。
class Solution {
public:int removeDuplicates(vector<int>& nums) {int j = 1;for (int i = 1; i < nums.size(); ++i){if (nums[i] != nums[i-1]){nums[j++] = nums[i];}}return j;}
};
7.4 只出现一次的数字II
只出现一次的数字II原题链接https://leetcode.cn/problems/single-number-ii/description/最简单的想法是,用哈希表存储每个元素出现的次数(7.1、7.5和7.6也可以用这种方式解决)。
class Solution {
public:int singleNumber(vector<int>& nums) {unordered_map<int, int> um;for (auto n : nums) ++um[n];for (auto& [n, cnt] : um)if (cnt == 1) return n;return 0;}
};
受到7.1题目的启发,考虑使用位运算求解本题。由于只有一个数字ret出现一次,其余数字出现三次,那么假设对所有数字二进制补码中的第i位求和为sum,就有两种情况:
- sum%3==0,说明ret的第i位是0;
- sum%3==1,说明ret的第i位是1。
这样就能获取到ret的每一位了。
class Solution {
public:int singleNumber(vector<int>& nums) {int ret = 0;for (int i = 0; i < 32; ++i){// 所有数字的第i位求和int sum = 0;for (auto n : nums)sum += ((n >> i) & 1);// 若求和后不是3的倍数,ret的第i位是1if (sum % 3)ret |= (1 << i);}return ret;}
};
7.5 只出现一次的数字III
只出现一次的数字III原题链接https://leetcode.cn/problems/single-number-iii/description/可以使用哈希表解决,但最优解依然是使用位运算。若把所有数异或到一块得到sum,假设sum二进制中的第i位是1。那么就可以把所有数字分成两组,其中一组的第i位是1,另一组的第i位是0,那么只出现一次的两个数字就被分到了不同的组中。把其中一组的所有数异或到一块去,就能得到其中一个只出现一次的数字,再把这个数字异或sum就能得到另一个只出现一次的数字。
其中,n&-n可以取出n的二进制中最低位的1,但是n=INT_MIN不能这么算,因为-n越界了,要单独考虑。INT_MIN的最高位是1,其余位都是0。
class Solution {
public:vector<int> singleNumber(vector<int>& nums) {int sum = 0;for (auto n : nums) sum ^= n;// 取出sum最低位的1// INT_MIN最低位的1是它本身// n&-n可以取出n最低位的1int bit = sum == INT_MIN ? INT_MIN : sum & -sum;int i = 0;for (auto n : nums)if (n & bit)i ^= n;return {i, i ^ sum};}
};
7.6 数组中出现次数超过一半的数字
数组中出现次数超过一半的数字原题链接https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&&tqId=11181&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking本题依然可以使用哈希表统计次数;也可以先排序,再找出中位数。
这里介绍一种算法:候选法。定义n为可能的众数,cnt为当前数字出现的次数。遍历数组,若当前元素和n相等,那么cnt++;若当前元素不等于n,那么cnt--。当cnt减到0时,就把n设置成当前元素,cnt设置成1。遍历完数组后,若有元素出现次数超过数组长度的一半,那么这个元素一定是n。由于题目描述中说明,一定有一个元素出现次数超过数组长度的一半,所以n为满足题目要求的元素。
class Solution {
public:int MoreThanHalfNum_Solution(vector<int>& numbers) {int n = 0, cnt = 0;for (auto num : numbers)if (cnt == 0) n = num, cnt = 1;else n == num ? ++cnt : --cnt;return n;}
};
7.7 电话号码的数字组合
电话号码的数字组合原题链接https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/维护一个字符串,取出每个数字字符对应的所有字母字符,并插入到字符串中。当digits中的所有数字字符都遍历完时,把得到的字符串插入到vector中,回退到上一层,找其余的字母排列。
如何取出每个数字对应的所有字母字符呢?可以考虑使用unordered_map,我这里使用vector,用下标对应数字,改下标对应的字符串表示所有可能的字母字符。建议定义成静态的成员变量,因为只需要维护一份vector,节省空间。
vector<string>和要维护的string建议先用reserve保留足够的空间,虽然本题用处不大,因为digits的size是在[0,4]的范围,扩容消耗不大。
class Solution {
public:vector<string> letterCombinations(string digits) {if (digits.empty()) return {};vector<string> coms;// 计算容量int newCapacity = 1;for (auto ch : digits){int n = ch - '0';newCapacity *= numToStr[n].size();}coms.reserve(newCapacity);string com;com.reserve(digits.size());Combinations(digits, 0, com, coms);return coms;}
private:void Combinations(const string& digits, int idx, string& com, vector<string>& coms){if (idx == digits.size()){coms.push_back(com);return;}int n = digits[idx] - '0';const string& str = numToStr[n];for (auto ch : str){com.push_back(ch);Combinations(digits, idx+1, com, coms);com.pop_back();}}static const vector<string> numToStr;
};const vector<string> Solution::numToStr = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
8. 模拟实现vector
8.1 迭代器
我们可以用3个迭代器来维护vector(SGI版本的STL就是这么实现的),并且给nullptr的缺省值。
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
其中iterator就是原生的指针。
typedef T* iterator;
typedef const T* const_iterator;
其中,_start标识空间的起始位置,_finish标识最后一个有效数据的位置,_end_of_storage标识空间的结束位置。举个例子,假设此时vector中的size是4,capacity是8,那么内存的大概分布如下:
1 2 3 4 ? ? ? ? !^ ^ ^
_start _finish _end_of_storage
那么几个关键位置就一目了然了。
iterator begin()
{return _start;
}iterator end()
{return _finish;
}const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
}
8.2 构造函数和析构函数
注意,v(5,10)可能会匹配迭代器区间构造函数,而不是按照n个val初始化的构造函数,所以要提供一个vector(size_t, const T&)的版本。
vector() = default;template<class InputIterator>
vector(InputIterator first, InputIterator last)
{while (first != last){push_back(*first);++first;}
}vector(size_t n, const T& val = T())
{reserve(n);while (n--){push_back(val);}
}vector(int n, const T& val = T())
{reserve(n);while (size() < n){push_back(val);}
}~vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}
}
8.3 拷贝构造和operator=
对于拷贝构造,我没有用现代写法,因为使用迭代器构造时的扩容会有消耗。注意不能使用memcpy直接按字节拷贝,因为T可能是自定义类型,memcpy会导致浅拷贝。
void swap(vector<T>& v)
{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);
}vector(const vector<T>& v):_start(new T[v.size()])
{_end_of_storage = _finish = _start + v.size();iterator it = begin();for (auto e : v){*it++ = e;}
}// 现代写法
//vector(const vector<T>& v)
//{
// vector<T> tmp(v.begin(), v.end());
// swap(tmp);
//}vector<T>& operator=(vector<T> tmp)
{swap(tmp);return *this;
}
8.4 容量相关接口
reserve在扩容时,不能使用memcpy拷贝数据,因为T可能是自定义类型,memcpy会导致浅拷贝。另外,由于size和capacity是指针相减计算得来的,扩容后更新_finish时不能写_finish=_start+size(),因为此时的_start已经改变,但是_finish还未更新,size会算出错误的结果。正确的做法是,提前记录size。
size_t size() const
{return _finish - _start;
}size_t capacity() const
{return _end_of_storage - _start;
}bool empty()
{return _start == _finish;
}void resize(size_t n, const T& val = T())
{if (n <= size()){_finish = _start + n;return;}if (n > capacity()){// 至少扩容2倍reserve(max(n, 2 * capacity()));}while (size() < n){push_back(val);}
}void reserve(size_t n)
{if (n > capacity()){// 扩容size_t sz = size();iterator tmp = new T[n];if (_start){// 拷贝数据for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}
}
8.5 访问相关接口
T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}const T& operator[](size_t pos) const
{assert(pos < size());return _start[pos];
}T& front()
{return *_start;
}const T& front() const
{return *_start;
}T& back()
{return *(_finish - 1);
}const T& back() const
{return *(_finish - 1);
}
8.6 插入和删除
insert插入时,先挪动数据再插入。注意reserve会导致迭代器失效,需要提前记录pos相对于_start的偏移量,reserve后需要对pos重新赋值。erase直接挪动数据覆盖即可。
挪动数据不能使用memcpy,因为T可能是自定义类型,memcpy会导致浅拷贝。
void push_back(const T& val)
{insert(end(), val);
}void pop_back()
{erase(end() - 1);
}iterator insert(iterator pos, const T& val = T())
{assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){// 扩容导致迭代器失效size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}// 挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;
}iterator erase(iterator pos)
{assert(pos >= _start);assert(pos < _finish);// 挪动数据,覆盖删除iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;
}
8.7 测试
观察调试窗口:
8.8 完整实现
#include<iostream>
#include<assert.h>
using namespace std;namespace xbl
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector() = default;template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()){reserve(n);while (n--){push_back(val);}}vector(int n, const T& val = T()){reserve(n);while (size() < n){push_back(val);}}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector(const vector<T>& v):_start(new T[v.size()]){_end_of_storage = _finish = _start + v.size();iterator it = begin();for (auto e : v){*it++ = e;}}// 现代写法//vector(const vector<T>& v)//{// vector<T> tmp(v.begin(), v.end());// swap(tmp);//}vector<T>& operator=(vector<T> tmp){swap(tmp);return *this;}size_t size() const{return _finish - _start;}size_t capacity() const{return _end_of_storage - _start;}bool empty(){return _start == _finish;}void resize(size_t n, const T& val = T()){if (n <= size()){_finish = _start + n;return;}if (n > capacity()){// 至少扩容2倍reserve(max(n, 2 * capacity()));}while (size() < n){push_back(val);}}void reserve(size_t n){if (n > capacity()){// 扩容size_t sz = size();iterator tmp = new T[n];if (_start){// 拷贝数据for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}T& front(){return *_start;}const T& front() const{return *_start;}T& back(){return *(_finish - 1);}const T& back() const{return *(_finish - 1);}void push_back(const T& val){insert(end(), val);}void pop_back(){erase(end() - 1);}iterator insert(iterator pos, const T& val = T()){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){// 扩容导致迭代器失效size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}// 挪动数据iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);// 挪动数据,覆盖删除iterator begin = pos + 1;while (begin < _finish){*(begin - 1) = *begin;++begin;}--_finish;return pos;}private:iterator _start = nullptr; // 有效数据起始位置iterator _finish = nullptr; // 有效数据结束位置iterator _end_of_storage = nullptr; // 空间结束位置};void test_vector(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);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 (auto e : v){cout << e << " ";}cout << endl;vector<int> v1(v);for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2;v2 = v1;for (auto e : v2){cout << e << " ";}cout << endl;vector<string> vs1;vs1.push_back("11111");vs1.push_back("22222");vs1.push_back("33333");vs1.push_back("44444");vs1.push_back("55555");for (auto e : vs1){cout << e << " ";}cout << endl;vector<string> vs2(vs1);for (auto e : vs2){cout << e << " ";}cout << endl;vector<string> vs3;vs3 = vs2;for (auto e : vs2){cout << e << " ";}cout << endl;vs3.pop_back();for (auto e : vs3){cout << e << " ";}cout << endl;vs3.pop_back();vs3.pop_back();vs3.pop_back();vs3.pop_back();//vs3.pop_back();vs3.push_back("666");vs3.push_back("777");vs3.push_back("888");for (auto e : vs3){cout << e << " ";}cout << endl;auto pos = find(vs3.begin(), vs3.end(), "777");if (pos != vs3.end()){vs3.erase(pos);}else{cout << "没找到" << endl;}for (auto e : vs3){cout << e << " ";}cout << endl;vector<int> v3;v3.resize(5);for (auto e : v3){cout << e << " ";}cout << endl;v3.resize(3);for (auto e : v3){cout << e << " ";}cout << endl;v3.resize(6, 1);for (auto e : v3){cout << e << " ";}cout << endl;vector<int> v4(10, 2);for (auto e : v4){cout << e << " ";}cout << endl;// 杨辉三角int height = 8;vector<vector<int>> vv1(8, vector<int>());for (int i = 0; i < vv1.size(); ++i){vv1[i].resize(i + 1, 0);vv1[i].front() = vv1[i].back() = 1;for (int j = 1; j < vv1[i].size() - 1; ++j){vv1[i][j] = vv1[i - 1][j - 1] + vv1[i - 1][j];}}for (const auto& v : vv1){for (auto n : v){cout << n << " ";}cout << endl;}vector<vector<int>> vv2(vv1);for (const auto& v : vv2){for (auto n : v){cout << n << " ";}cout << endl;}vector<vector<int>> vv3;vv3 = vv2;for (const auto& v : vv3){for (auto n : v){cout << n << " ";}cout << endl;}}
}
输出:
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
11111 22222 33333 44444 55555
11111 22222 33333 44444 55555
11111 22222 33333 44444 55555
11111 22222 33333 44444
666 777 888
666 888
0 0 0 0 0
0 0 0
0 0 0 1 1 1
2 2 2 2 2 2 2 2 2 2
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1