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来初始化vector
for (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指向30
cout << *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; // 指向5
v.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位是1
if (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最低位的1
int 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