由于STL中很多容器的接口与string类似,功能类似,所以只讲重点的接口。
vector v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.insert(v.begin(), 0);
v.insert(v.begin()+1, 0);
v.erase(v.begin() + 1);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
//程序运行结果:0 1 2 3 4
如果要删除指定的元素,怎么办?vector没有find接口,但算法有find。
find可以在迭代器区间找想要的值,如果找到,就返回其迭代器;找不到,就返回last(end())。注意:迭代器区间是左闭右开的,[first,last)。
//找到值为2的元素,并删除
vector::iterator vit = find(v.begin(), v.end(), 2);
v.erase(vit);
for (auto e : v)
{
cout << e << " ";
}
cout<
vector v1(10,1);
for (size_t i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//运行结果1 1 1 1 1 1 1 1 1 1
#include
#include
using namespace std;
namespace zn
{
template
class vector
{
typedef T* iterator;
typedef const T* const_iterator;
private:
iterator _start;//指向序列的首元素
iterator _finish;//指向序列的最后一个元素的下一个位置,相当于size
iterator _endOfStorage;//指向序列的容量空间的下一个位置,相当于capacity
public:
//构造
vector()
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{}
vector(size_t n, const T& value = T())
:_start(nullptr)
, _finish(nullptr)
, _endOfStorage(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; i++)
{
push_back(_start[i]);
}
}
vector(const vector&v)
:_start(nullptr)
,_finish(nullptr)
,_endOfStorage(nullptr)
{
reserve(v.capacity());
iterator it = v.begin();
while (it != v.end())
{
push_back(*it);
}
}
//交换
void swap(vector& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endOfStorage, v._endOfStorage);
}
//赋值
vector& operator=(vector v)
{
swap(v);
return *this;
}
//析构
~vector()
{
//还得判断是否是null。因为可能存在vector对象只调用默认构造,
//没有操作就调用析构的情况。
if (_start)
{
delete[]_start;
_start = _finish = _endOfStorage;
}
}
//迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin()const
{
return _start;
}
const_iterator end()const
{
return _finish;
}
//访问
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
//扩容
size_t size()
{
return _finish - _start;
}
size_t capacity()
{
return _endOfStorage - _start;
}
//这里用memcpy还有问题,后面讲
void reserve(size_t n)
{
if (n > 0)
{
int len = _start - _finish;
T* tmp = new T[n];
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
_start = tmp;
//此时_finish和_endOfStorage还指向原来的旧空间
_finish = _start + len;
_endOfStorage = _start + n;
}
}
//尾插
void push_back(const T& val)
{
if (size() == capacity())
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = val;
++_finish;
}
//插入
iterator insert(iterator pos,const T&x)
{
assert(pos >= _start && pos < _finish);
if (size() == capacity())
{
//如果扩容,就会出现问题:迭代器失效。
//迭代器失效:扩容后,迭代器还指向旧空间。这里扩容后还指向旧空间。
//解决方法:将pos指向新的空间的相对位置。
size_t relaPos = pos - _start;
size_t len = _finish - _start;
T* tmp = new T[capacity() * 2];
memcpy(tmp, _start, sizeof(T) * size());
_start = tmp;
_finish = _start + len;
_endOfStorage = _start + capacity() * 2;
pos = _start + relaPos;
}
iterator end = _finish-1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
//返回可能更新的迭代器,防止再被使用时失效了
return pos;
}
//删除
void erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos + 1;
while (it != end())
{
*(it - 1) = *it;
++it;
}
--_finish;
}
//------------------------------------------------------------------
//(1)删除,涉及到迭代器失效。
//(2)迭代器失效:当删除某个迭代器指向的值后,该迭代器后面的值往前挪一位,
//此时迭代器不再指向原来的值,迭代器就失效了。
//(3)如果要删除的迭代器刚好指向最后一个元素,删除后再对该迭代器进行访问,
//就会报错,因为越界。
//(4)因此,虽然迭代器失效,代码不一定崩溃,但其运行结果肯定不对。在一些
//平台,删除所导致的迭代器失效是不报错。
//(5)总结:在使用insert、erase等操作后,不要使用原来的迭代器参数,如果
//一定要使用,就返回新的迭代器迭代器,对迭代器进行重新赋值。
//------------------------------------------------------------------
//尾删
void pop_back()
{
erase(--end());
}
//调整大小
//T()是匿名对象,T是自定义类型,会调用默认构造,
//如果是内置类型?内置类型升级,有默认构造函数,
//也会调用默认构造
void resize(size_t n, const T& val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
reserve(n);
while (_finish != _start + n)
{
*_finish = val;
++_finish;
}
}
}
};
};
在上面的模拟实现vector中,提到memcpy来扩容有问题,由于当时不方便,拿到这里来讨论。
void test()
{
vector vs;
vs.push_back("1234");
vs.push_back("2345");
vs.push_back("3456");
vs.push_back("4567");
//开始扩容
vs.push_back("5678");
}
void reserve(size_t n)
{
if (n > 0)
{
int len = _start - _finish;
T* tmp = new T[n];
for(size_t i = 0;i
//思路:a ^ a = 0,0 ^ b = b,a ^ b ^ a = a ^ a ^ b = 0 ^ b = b(交换律)。
//数组中其他数字出现两次,只有一次数字出现一次,将他们全部异或,就得到那个出现一次的数。
class Solution {
public:
int singleNumber(vector& nums) {
for(size_t i = 1;i
class Solution {
public:
vector> generate(int numRows) {
//思路:第i行开辟i+1个空间
vector> vv;
//开辟n行
vv.resize(numRows);//开辟空间的同时改变size,为下面访问奠定基础,而reserve只是开辟空间,size没有改变
for(size_t i = 0;i
class Solution {
public:
const char* ch[10] = { "","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
//level记录digits中第几个号码,tmp用来累加每个号码对应的字母,最后当level
//==号码个数时,tmp已经记录好一组字符串了,这时就可以加到vs。
void Combine(string digits,int level,string tmp,vector& vs)
{
if(level == digits.size())
{
vs.push_back(tmp);
return ;
}
int num = digits[level] - '0';
string str = ch[num];
for(size_t i = 0;i letterCombinations(string digits) {
//思路:利用多路递归来实现
vector vs;
if(digits.empty())
{
return vs;
}
string tmp;
Combine(digits,0,tmp,vs);
return vs;
}
};