C++ 序列容器Vector各种方法实现原理(带你从本质理解Vector容器)
vector容器与动态数组相同,在插入或者删除元素的时候能够自动调整容器大小,即vector容器能够自动处理存储数据所需要的空间。vector容器中的元素放在连续的内存空间中,可以使用迭代器对其进行访问和遍历。
序列容器也叫做顺序容器,序列容器各元素之间有顺序关系,每个元素都有固定的位置,除非使用插入或删除元素改变这个元素的位置。序列容器是一种线性结构的有序群集,它最重要的特点就是可以在容器一端增加和删除元素。
文章目录
一.Vector容器简介
vector容器与动态数组相同,在插入或者删除元素的时候能够自动调整容器大小,即vector容器能够自动处理存储数据所需要的空间。vector容器中的元素放在连续的内存空间中,可以使用迭代器对其进行访问和遍历。
二.标准模板库中对vector容器的操作
**在使用vector容器时,需要包含vector头文件:
#incldue<vector>
1.创建vector容器
vector模板中定义了多个重载构造函数,因此vector容器的创建方式有很多种。vector容器的创建方式主要有四种:
<1>.指定容器大小
指定容器大小的格式:vector <元素类型> 对象名(容器大小);
注意这里的容器大小是指定元素类型的容器有多少个。
注意: vector容器在定义后所有元素都会被初始化,如果是基本类型数据,那么会被初始化为0,如果是其他类,则会被该类默认的构造函数完成初始化。
<2>.指定初始值
在创建vector容器时,可以同时指定vector容器大小和初始值,其格式为:
vector <元素类型> 对象名 (容器大小,元素初始值);
在这里,会将容器中所有的元素都初始化为元素初始值。
<3>.列表初始化
C++11标准还提供了另一种定中vector容器初始化的方式,即使用值的列表进行初始化,示例代码如下所示:
vector <int> v1{1,2,3,4,5,6}; //v1有六个元素
vector <int> v2={"a","b","c"}; //v2有三个元素
<4>.初始化状态为空
初始化状态为空,即创建vector容器即不指定大小也不指定初始值,示例代码如下所示:
vector <int> v1;
<5>.用一个vector容器初始化另一个vector容器
除了上述方式,vector容器还可以用另一个vector容器完成初始化,示例代码如下所示:
vector <int> v1(10,1);
vector <int> v2(v1); //用v1初始化v2
vector <int> v3 = v2; //用v2初始化v3
2.获取容器容量和实际元素个数
vector容器的容量与容器实际的元素个数并不一定相同(我们在后文中自己实现vector容器的时候大家自会理解),容器容量表示容器一共能存储的元素个数,是容器预分配的内存空间。而容器实际元素个数可能小于容器容量。
vector提供了两个函数capacity()
和size()
,分别用于获取容器容量和实际元素个数,这两个函数的调用格式如下所示:
v.capacity();
v.size();
上述代码中,v是创建的vector容器。capacity()
函数返回容器的容量,size()
函数返回容器实际元素个数。
3.访问容器中的元素
由于vector重载了[]运算符,因此可以使用索引的方式访问vector容器中的元素。
此外,vector还提供了一个成员函数at()
,用于随机访问容器中的元素。at()
函数的调用方式如下所示:
v.at(int idx);
其中idx表示索引。at()函数返回值为索引指向的数据。
4.赋值函数
vector容器中的元素可以在创建容器时指定,也可以通过[]运算符来完成。除此之外vector还提供了一个成员函数assign()
,用于给空的vector容器赋值。assign()
函数有两种重载方式:
v.assign(n,elem);
c.assign(begin,end);
第一种形式给元素赋同样的初始值,第二种方式以指定区间给元素赋值。需要注意的是,区间是左闭右开,即第一个区间值可以使用,最后一个区间值不可使用。
5.获取头部和尾部元素
vector容器提供了front()
函数与back()
函数,分别用于获取容器的头,尾元素。front()
函数与back()
函数的调用形式如下图所示:
v.front();
c.back();
6.从尾部插入和删除元素
vector容器提供了一对函数push_back()
与pop_back()
,分别用于从尾部添加元素和删除尾部元素,它们的调用形式如下图所示:
v.push_back(type elem& t);
v.pop_back();
7.在任意位置插入和删除元素
vector提供了像容器任意位置插入和删除元素的函数insert()
与erase()
。其中,insert()
函数用于向容器中插入元素,它有三种重载形式:
v.insert(pos,elem); //在pos位置插入元素elem
v.insert(pos,n,elem); //在pos位置插入n个elem元素
v.insert(pos,begin,end); //在pos位置插入[begin,end)区间的数据
erase函数用于删除容器中的元素,它有两种重载方式:
v.earse(pos); //删除pos位置上的元素
v.earse(begin,end); //删除[begin,end)区间上的元素
注意: insert()
函数与earse()
函数中的位置参数只能由begin()
,end()
等函数返回的迭代器只是,不能使用纯粹的数字。
三.vector容器各类方法的实现
由于我们做逆向的人必须理解本质,不然的话如果逆向出来代码,也不知道这是vector的方法,源码贴在这里,源码中有详细的分析,大家自行阅读一边,会有更深的理解。
#include<iostream>
#include<windows.h>
#define success 1
#define error 0
using namespace std;
template <class T_ELE>
class vector{
public:
vector();
vector(DWORD dwsize);
~vector();
private:
DWORD m_dwIndex; //下一个可用索引
DWORD m_dwIncrement; //每次增加的容量
DWORD m_dwLen; //当前容器的实际大小
DWORD m_dwInitSize; //默认初始化的大小
int *pvector; //容器指针
public:
DWORD capacity(); //获取当前容器容量
DWORD size(); //当前容器实际元素个数
DWORD push_back(T_ELE Elment); //向容器尾部添加元素(如果需要增容,需要调用增容函数)
DWORD insert(DWORD dwIndex,T_ELE Element); //向指定位置添加元素
void pop_back(); //删除容器末尾元素
DWORD erease(DWORD dwIndex); //删除指定元素
void at(DWORD dwIndex); //根据索引得到元素
void clean(); //清空容器
private:
bool expand();
};
template <class T_ELE>
vector<T_ELE>::vector()
:m_dwInitSize(100),m_dwIncrement(5){
//创建长度为m_dwInitSize个T_ELE对象,在堆中申请内存
pvector = new T_ELE[m_dwInitSize];
//初始化申请的内存
memset(pvector,0,m_dwInitSize*sizeof(T_ELE));
//设置其他值
m_dwLen = 100;
m_dwIndex = 0;
cout<<"无参构造函数完成。"<<endl;
}
template <class T_ELE>
vector<T_ELE>::vector(DWORD dwsize)
:m_dwIncrement(5){
//创建长度为dwsize个T_ELE对象,在堆中申请内存
pvector = new T_ELE[dwsize];
//初始化申请的内存
memset(pvector,0,dwsize*sizeof(T_ELE));
//设置其他值
m_dwLen = dwsize;
m_dwIndex = 0;
cout<<"有参构造函数完成。"<<endl;
}
template <class T_ELE>
vector<T_ELE>::~vector(){
delete pvector;
pvector = NULL;
cout<<"析构函数完成。"<<endl;
}
template <class T_ELE>
bool vector<T_ELE>::expand(){
//计算增加后的长度
int dwTempLen = m_dwLen + m_dwIncrement;
//申请内存
T_ELE* ptemp = new T_ELE[dwTempLen];
//初始化申请的内存
memset(ptemp,0,dwTempLen*sizeof(T_ELE));
//复制原始内存中的值
memcpy(ptemp,pvector,m_dwLen*sizeof(T_ELE));
//释放原来空间,更新指针
delete[] pvector;
pvector = ptemp;
ptemp = NULL;
//修改其它属性
m_dwLen = dwTempLen;
cout<<"增容操作完成。"<<endl;
return success;
}
template <class T_ELE>
DWORD vector<T_ELE>::push_back(T_ELE Element){
//判断是否需要增容
if(m_dwIndex>=m_dwLen)expand();
//将新元素复制到容器最后一个位置
memcpy(&pvector[m_dwIndex],&Element,sizeof(T_ELE));
//修改其他属性
m_dwIndex++;
m_dwLen++;
return success;
}
template <class T_ELE>
DWORD vector<T_ELE>::insert(DWORD dwIndex,T_ELE Element){
//判断是否需要扩容
if(m_dwIndex >= m_dwLen)expand();
//判断索引是否合理
if(dwIndex<0 || dwIndex>m_dwIndex){
cout<<"索引不合理。"<<endl;
return error;
}
//将dwIndex之后的元素移动
//memset(&pvector[dwIndex],pvector,((m_dwIndex-dwIndex)*sizeof(T_ELE)));
for(int i=m_dwIndex;i>=0;i--){
memcpy(&pvector[i+1],&pvector[i],sizeof(T_ELE));
}
m_dwIndex++;
//将Element复制到dwIndex
pvector[dwIndex] = Element;
//修改属性值
m_dwLen++;
cout<<"添加元素成功。"<<endl;
return success;
}
template <class T_ELE>
void vector<T_ELE>::at(DWORD dwIndex){
//判断索引是否在合理区间
if(dwIndex<0 || dwIndex>=m_dwIndex){
cout<<"索引不合理"<<endl;
return error;
}
//显示dwIndex的值并返回
cout<<pvector[dwIndex]<<endl;
return pvector[dwIndex];
}
template <class T_ELE>
void vector<T_ELE>::clean(){
delete[] pvector;
}
void Test(){
vector<int>* v1 = new vector<int>(5);
v1->push_back(0);
v1->push_back(1);
v1->push_back(2);
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->insert(3,3);
}
int main(){
Test();
return 0;
}
更多推荐
所有评论(0)