#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
int main()
{
vector<int> v;// 无参构造
vector<int> vc(6, '1');//构造并初始化6个'1'
vector<int> v2(v.begin(), v.end());//使用迭代器进行初始化构造
vector<int> v4(v);//拷贝构造
return 0;
}
注:
vector和string的区别:vector里面给char,虽然他们底层都是数组中存char但是还是不一样的,s对象中指向的空间结尾有’\0’
使用迭代器进行初始化构造:使用其他容器迭代器初始化,只要数据类型可以匹配上(*iterator对象的类型跟vector中存的数据类型一致)就可以
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//迭代器
vector<int>::iterator it = v.begin(); //begin和end
while (it != v.end())
{
cout << *it << " "; //1 2 3 4 5
it++;
}
cout << endl;
vector<int>::reverse_iterator rit = v.rbegin(); //rbegin和rend
while (rit != v.rend())
{
cout << *rit << " "; //5 4 3 2 1
rit++;
}
cout << endl;
const vector<int> v1(6, 1); //const修饰的对象
vector<int>::const_iterator cit = v1.begin();
while (cit != v1.end())
{
cout << *cit << " ";
++cit;
}
cout << endl;
vector<int>::const_reverse_iterator crit = v1.crbegin();
while (crit != v1.crend())
{
cout << *crit << " ";
++crit;
}
cout << endl;
return 0;
}
注:
it是原生指针;rit不是原生指针,rit是被封装的类对象,重载operator++才能实现rit++,是倒着走的。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);// 尾插
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.pop_back(); //尾删
for (size_t i = 0;i < v.size();i++)
{
cout << v[i] << " "; //operator[]
}
cout << endl;
// 使用find查找3所在位置的iterator
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
// 在pos位置之前插入30
v.insert(pos, 30);
vector<int>::iterator it = v.begin();
while (it != v.end()) {
cout << *it << " ";
++it;
}
cout << endl;
pos = find(v.begin(), v.end(), 3);
// 删除pos位置的数据
v.erase(pos);
it = v.begin();
while (it != v.end()) {
cout << *it << " ";
++it;
}
cout << endl;
vector<int> v1(6, 1);
vector<int> v2(6, 6);
swap(v1, v2); //swap交换两个数组
return 0;
}
注:
operator[]中会去检查index是否小于size
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
int main()
{
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
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
return 0;
}
注:operator[]+index 和 C++11中vector的新式for+auto的遍历;vector使用这两种遍历方式是比较便捷的。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
using namespace std;
int main()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
cout << v.capacity() << endl; //查看容量
cout << v.empty() << endl;//查看数组是否为空
cout << v.size() << endl;// 查看数组中有效元素个数
cout << v.max_size() << endl; //最大数组容纳该类型元素的个数
v.reserve(10);//开空间,改变容量
v.resize(20);//开空间+初始化
v.resize(20,1);
return 0;
}
注:
- capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。这个问题经常会考察,不要固化的认为,顺序表增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。
- reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题。
- resize在开空间的同时还会进行初始化,影响size。
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
using namespace std;
int main()
{
int a[] = { 1,2,3,4,5 };
vector<int> v;
v.assign(a, a + 4);//assgin相当于赋值重载
v.insert(v.begin(), 0); //相当于头插
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
v.erase(v.begin());//头删
vector<int>::iterator pos = find(v.begin(), v.end(), 2);
if (pos != v.end())
{
v.erase(pos);
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
//默认是升序
sort(v.begin(), v.end());
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
//排降序-greater是一个仿函数类
sort(v.begin(), v.end(), greater<int>());
/*greater gt;
sort(v.begin(), v.end(), gt);*/
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
//指向数组空间的指针是天然的迭代器
int arr[] = { 30,4,5,60,10 };
sort(arr, arr + 5);
for (auto e : arr)
{
cout << e << " ";
}
cout << endl;
return 0;
}
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。
1. 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。
#include
using namespace std;
#include
int main()
{
vector<int> v{ 1,2,3,4,5,6 };
auto it = v.begin();
// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
// v.resize(100, 8);
// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变
// v.reserve(100);
// 插入元素期间,可能会引起扩容,而导致原空间被释放
// v.insert(v.begin(), 0);
//insert以后pos就失效了 ---insert增容导致的
//lc::test();
// v.push_back(8);
// 给vector重新赋值,可能会引起底层容量改变
v.assign(100, 8);
/*
出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。
解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。
*/
while (it != v.end())
{
cout << *it << " ";
++it;
}
cout << endl;
return 0;
}
总结:
2. 指定位置元素的删除操作–erase
注:
总结:
vector的核心框架接口的模拟实现:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
using namespace std;
namespace lc
{
template <class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
vector()
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{}
template<class InputIterator>
vector(InputIterator first, InputIterator last)
: _start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
while (first != end)
{
push_back(*first);
++first;
}
}
拷贝构造1.传统写法
//vector(const vector& v)
// :_start(nullptr)
// ,_finish(nullptr)
// ,_endofstorage(nullptr)
//{
// _start = new T[v.capacity()];
// for (int i = 0;i < v.size();i++)
// {
// _start[i]=v[i];
// }
// _finish = _start+v.size();
// _endofstorage = _start + v.capacity();
//}
//2. 传统写法
vector(const vector<T>& v)
:_start(nullptr)
, _finish(nullptr)
, _endofstorage(nullptr)
{
reserve(v.capacity());
for (const auto& e: v)
{
push_back(e);
}
}
3.现代写法
//vector(const vector& v)
// :_start(nullptr)
// , _finish(nullptr)
// , _endofstorage(nullptr)
//{
// vector tmp(v.begin(), v.end());
// swap(tmp);
//}
赋值重载1.传统写法
/*vector& operator=(const vector& v)
{
if (this != &v)
{
if (capacity() < v.size())
{
reserve(v.size());
}
for (int i = 0;i < v.size();i++)
{
_start[i]=v[i];
}
_finish = _start + v.size();
_endofstorage = _start + capacity();
}
return *this;
}*/
//2.传统写法
/*vector& operator=(const vector& v)
{
if (this != &v)
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
reserve(v.capacity());
for (const auto& e : v)
{
push_back(e);
}
}
return *this;
}*/
// 3.现代写法
vector<T>& operator=(vector<T> v)
{
swap(v);
return *this;
}
~vector()
{
delete[] _start;
_start = _finish = _endofstorage = nullptr;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_endofstorage, v._endofstorage);
}
iterator begin()
{
return _start;
}
const_iterator begin()const
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator end()const
{
return _finish;
}
T& operator [](size_t i)
{
assert(i < size());
return _start[i];
}
const T& operator [](size_t i)const
{
assert(i < size());
return _start[i];
}
size_t size()const
{
return _finish - _start;
}
size_t capacity()const
{
return _endofstorage - _start;
}
//只开空间
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
//T->int double等类型
//memcpy(tmp, _start, sizeof(T) * sz);
for (int i = 0;i < sz;i++)
{
//如果T是string调用的就是string的operator=(深拷贝)
//
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endofstorage = _start+n;
}
}
void push_back(const T& x)
{
if (_finish == _endofstorage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newcapacity);
}
*_finish = x;
_finish++;
// insert(_finish, x);
}
//开空间+初始化
void resize(size_t n, const T& val =T())
{
if (n <= size())
{
_finish = _start + n;
}
else
{
if (n > capacity())
{
reserve(n);
}
while (_finish < _start+n)
{
*_finish = val;
_finish++;
}
}
}
bool empty() const
{
return _finish - _start == 0;
}
void pop_back()
{
assert(!empty());
_finish--;
//erase(end()--);
}
iterator insert(iterator pos, const T& x)
{
assert(pos >= _start && pos <= _finish);
if (_finish == _endofstorage)
{
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newcapacity);
pos = _start + len;
}
iterator it = _finish;
while (it>pos)
{
*it = *(it - 1);
it--;
}
*pos = x;
_finish++;
return pos;
}
iterator erase(iterator pos)
{
assert(pos >= _start && pos < _finish);
iterator it = pos;
while (it<_finish-1)
{
*it = *(it + 1);
it++;
}
_finish--;
return pos;
}
private:
iterator _start;
iterator _finish;
iterator _endofstorage;
};
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * sz);
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_endofstorage = _start + n;
}
}
void test4()
{
vector<string> v;
v.reserve(4);
v.push_back("11111");
v.push_back("11111");
v.push_back("11111");
v.push_back("11111");
v.push_back("11111"); //增容
for (const auto& e : v)
{
cout << e << " ";
}
cout << endl;
}
总结:
如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起野指针问题甚至程序崩溃。