文章目录
🚩前言
前面描述了字符串string的相关知识,接下来描述第二个常用容器——vector,即顺序表。👇👇
1、vector容器的概述
- 简单来说,vector相当于C++中的数组,数组中可以用的操作,在vector中都有相应的接口,并且具有数组没有的功能,基于数组的数据结构实现自动管理内存的,方便灵活的序列容器。
2、vector构造函数的使用
首先了解vector可以支持的构造函数有哪些?下面是所具有的构造函数:
//构造函数的使用
void Test_vector_1()
{
//构造一个空的容器
vector<int> v1;
//构造n个值为val的容器
vector<int> v2(8,6);
//使用迭代器构造一个容器,可以改变范围大小
vector<int> v3(++v2.begin(), --v2.end());
}
调试结果
3、vector遍历方式
在vector中和string遍历方式一样的,都包括下标访问、迭代器以及范围for访问,接下来使用一下这些访问方式:
//遍历方式的使用
void Test_vector_2()
{
//创建一个大小为10,值为6的容器
vector<int> v1(10,6);
//下标访问
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
//迭代器
vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
cout << *it << " ";
++it;
}
cout << endl;
//范围for遍历
for (auto n : v1)
{
cout << n << " ";
}
cout << endl;
}
4、vector中Capacity相关接口
通过reserve接口来了解:
//Capacity相关接口
void Test_vector_3()
{
vector<int> v1(10,1);
//先看原始空间大小
cout <<"_size:"<< v1.size() << endl;
cout << "_capacity:"<<v1.capacity() << endl;
//申请更大空间
v1.reserve(30);
cout << "预留大于空间的,空间变大:" << endl;
cout <<"_size:"<< v1.size() << endl;
cout << "_capacity:"<<v1.capacity() << endl;
cout << "预留比空间小的,空间不会缩容的:" << endl;
v1.reserve(20);
cout << "_size:" << v1.size() << endl;
cout << "_capacity:" << v1.capacity() << endl;
}
resize()接口的作用
主要有两种:①resize的个数小于原本数据个数的时候,就相当于删除后面的数据内容,在vs上空间不会缩容(缩容和不缩容得看编译器平台);②若大于原本数据个数的时候,就是插入,当空间不够的时候就会扩容;
//resize()
void Test_vector_3()
{
vector<int> v1(10, 1);
//先看原始空间大小
cout << "_size:" << v1.size() << endl;
cout << "_capacity:" << v1.capacity() << endl;
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "大于原有数据个数的时候,超过原有空间大小:" << endl;
v1.resize(15,2);
cout << "_size:" << v1.size() << endl;
cout << "_capacity:" << v1.capacity() << endl;
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "小于原有数据个数的时候,不会缩容:" << endl;
v1.resize(5);
cout << "_size:" << v1.size() << endl;
cout << "_capacity:" << v1.capacity() << endl;
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
}
5、vector插入和删除的使用
插入接口主要是:push_back()和insert(),删除就是:erase();
//插入和删除
void Test_vector_4()
{
vector<int> v1;
cout << "size:" << v1.size() << endl;
cout << "capacity:" << v1.capacity() << endl;
cout << endl;
//尾插
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
v1.push_back(6);
v1.push_back(7);
v1.push_back(8);
v1.push_back(9);
v1.push_back(10);
v1.push_back(11);
cout << "尾插:" << endl;
for (auto n : v1)
{
cout << n << " ";
}
cout << endl;
cout << "size:" << v1.size() << endl;
cout << "capacity:" << v1.capacity() << endl;
cout << endl;
//固定插入
cout << "首部插入:" << endl;
v1.insert(v1.begin(),10);
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "中间位置插入:" << endl;
v1.insert(v1.begin()+4, 666);
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "erase支持某一位置删除和区间删除:" << endl;
cout << "删除第一个元素:"<<endl;
v1.erase(v1.begin());
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "删除最后一个元素:" << endl;
v1.erase(v1.end()-1);
v1.erase(v1.begin());
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "区间删除:" << endl;
v1.erase(v1.begin()+3,v1.begin()+5);
for (auto n : v1)
{
cout << n << " ";
}
cout << endl << endl;
cout << "清空接口,不改变空间:clear()" << endl;
v1.clear();
cout <<"size:"<< v1.size() << endl;
cout << "capacity:"<<v1.capacity() << endl;
cout << endl;
}
常用常用接口就描述到此,不常见的可以通过下面链接了解:
✨模拟实现vector简单接口
此次的模拟实现包括:迭代器遍、增删接口、空间大小改变等。通过类模版+命名空间域,以便和库里的vector区别。
再代码编写的时候容易出现迭代器失效的问题,特别是在插入和删除的时候,在代码注释中有解释;
#pragma once
#include<assert.h>
namespace zc
{
template<class T>
class my_vector
{
public:
typedef T* iterator;
typedef T* const_iterator;
//无参构造函数
my_vector() {};
//n个值构造函数
my_vector(int n, const T& value = T());
//迭代器区间构造函数
template<class input_iterator>
my_vector(input_iterator first,input_iterator last);
//拷贝构造函数
my_vector(const my_vector<T>& v);
//赋值拷贝构造函数
my_vector<T>& operator=(my_vector<T> v);
//析构函数
~my_vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage;
}
}
void reserve(size_t n);
//有效数据个数
size_t size()const
{
return _finish - _start;
}
//有效空间
size_t capacity()const
{
return _end_of_storage - _start;
}
//改变容器大小
void resize(size_t n,const T& value = T());
//迭代器访问接口
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
//const迭代器
const_iterator begin()const
{
return _start;
}
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];
}
bool empty()
{
return _finish == _start;
}
void swap(my_vector<T>& v)
{
//调用库里面的
std::swap(_start,v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
//增删查函数接口
void push_back(const T& x);
void pop_back()
{
assert(!empty());
--_finish;
}
iterator insert(iterator pos, const T& x);
iterator erase(iterator pos);
private:
iterator _start=nullptr;
iterator _finish=nullptr;
iterator _end_of_storage=nullptr;
};
template<class T>
void print_vector(const my_vector<T>& v)
{
typename my_vector<T>::const_iterator it = v.begin();
while (it != v.end())
{
std::cout << *it << " ";
++it;
}
std::cout << std::endl;
}
template<class T>
inline my_vector<T>::my_vector(int n, const T& value)
{
reserve(n);
for (int i = 0; i < n; i++)
{
push_back(value);
}
}
template<class T>
inline my_vector<T>::my_vector(const my_vector<T>& v)
{
//先开辟与拷贝对象中数据个数的空间
reserve(size());
//直接插入值
for (auto vv : v)
{
push_back(vv);
}
}
template<class T>
inline my_vector<T>& my_vector<T>::operator=(my_vector<T> v)
{
swap(v);
return *this;
}
template<class T>
inline void my_vector<T>::reserve(size_t n)
{
if (n > capacity())
{
//注意size()的改变,需要先计算出old_size保存起来,再赋值给新空间中
size_t old_size = size();
//1、开辟新空间
T* tmp = new T[n];
//2、拷贝新空间,此处memcpy()对于要深拷贝的数据,就无法完成,因此要用赋值
for (int i = 0; i < size(); i++)
{
//把原来空间中的数据拷贝过来
tmp[i] = _start[i];
}
//3、释放就空间
delete[] _start;
//4、修改末尾大小和空间大小
_start = tmp;
_finish = tmp + old_size;//若此处还用size(),那么会崩掉,因为此时_start已经是新空间的了,size()中计算是_finish-_start;
_end_of_storage = _start + n;
}
}
template<class T>
inline void my_vector<T>::resize(size_t n,const T& value)
{
//当n<_finish时或小于size()有效个数,相当于删除数据
if (n < size())
{
_finish = _start + n;
}
else
{
//此处两种情况,1:在_finish和_end_of_storage之间,2:大于整个空间大小,则需要扩容
//因此不管哪种直接调用reserve(),里面有检查机制,在两者之间的时候是不会扩容的
reserve(n);
//然后直接在末尾插入数据
while (_finish < _start + n)
{
*_finish = value;
++_finish;
}
}
}
template<class T>
inline void my_vector<T>::push_back(const T& x)
{
//扩容
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = x;
++_finish;
}
//在类外不能去没有实例化的类模版里面取东西,编译器不能区分此处的iterator是类型还是静态成员变量,
// 需要用my_vector范围限定以及typename修饰,也可以整体写为auto,自动推导
template<class T>
inline typename my_vector<T>::iterator my_vector<T>::insert(typename my_vector<T>::iterator pos, const T& x)
{
//检查插入位置是否合理
assert(pos >= _start && pos <= _finish);
//扩容之前pos需哟可临时存起来,记录好相对位置,因为扩容后会导致pos失去原来的意义
size_t len = pos - _start;
//扩容机制
if (_finish == _end_of_storage)
{
reserve(capacity()==0?4:2*capacity());
}
//移动位置
pos = _start + len;
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end;
--end;
}
*pos = x;
++_finish;
return pos;
}
template<class T>
inline typename my_vector<T>::iterator my_vector<T>::erase(typename my_vector<T>::iterator pos)
{
//检查删除位置合法性
assert(pos>=_start&&pos<_finish);
//移动数据
iterator begin = pos + 1;
while (begin <= end())
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
return pos;
}
template<class T>
template<class input_iterator>
inline my_vector<T>::my_vector(input_iterator first, input_iterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
}
测试代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include"my_vector.h"
void test_1()
{
zc::my_vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
std::cout << "v1容器下标访问:";
for (int i = 0; i < v1.size(); i++)
{
std::cout << v1[i] << " " ;
}
std::cout << std::endl;
std::cout << "v1容器迭代器访问:";
zc::my_vector<int>::iterator it = v1.begin();
while (it != v1.end())
{
std::cout << *it << " ";
++it;
}
std::cout<<std::endl;
std::cout << "v1容器范围for访问:";
for (int& x : v1)
{
std::cout << x << " ";
}
std::cout << std::endl;
/*std::cout << "v1容器删除数据:";
v1.pop_back();
v1.pop_back();
print_vector(v1);*/
zc::my_vector<int> v2(v1.begin()+1,v1.begin()+3);
std::cout << "v2容器迭代器区间构造:";
print_vector(v2);
zc::my_vector<int> v3(10,6);
std::cout << "v3容器n个值构造:";
print_vector(v3);
zc::my_vector<int> v4=v3;
std::cout << "v4容器拷贝构造:";
print_vector(v4);
zc::my_vector<int> v5;
v5 = v2;
std::cout << "v5容器赋值拷贝:";
print_vector(v5);
std::cout << "v1插入数据:";
v1.insert(v1.begin()+5, 66);
v1.insert(v1.begin() + 2, 99);
print_vector(v1);
std::cout << "v3删除数据:";
v3.erase(v3.begin() + 4);
v3.erase(v3.begin() + 5);
v3.erase(v3.begin() + 6);
print_vector(v3);
std::cout << std::endl;
std::cout << "改变v1容器大小:" << std::endl;
std::cout << "v1原始空间大小:" << v1.capacity() << std::endl;
std::cout << "v1原始有效个数:" << v1.size() << std::endl;
print_vector(v1);
v1.resize(11,5);
std::cout << "v1改变后空间大小:" << v1.capacity() << std::endl;
std::cout << "v1改变后有效个数:" << v1.size() << std::endl;
print_vector(v1);
}
void test_2()
{
zc::my_vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::cout << "v原始空间大小:" << v.capacity() << std::endl;
std::cout << "v原始有效个数:" << v.size() << std::endl;
print_vector(v);
v.resize(7,1);
std::cout << "v现在空间大小:" << v.capacity() << std::endl;
std::cout << "v现在有效个数:" << v.size() << std::endl;
print_vector(v);
}
void test_3()
{
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::cout << v.capacity() << std::endl;
std::cout << v.size() << std::endl;
v.resize(7,1);
std::cout << v.capacity() << std::endl;
std::cout << v.size() << std::endl;
}
int main()
{
test_1();
//test_2();
//test_3();
return 0;
}