顺序容器——vector
作者:互联网
#include <iostream>
#include <vector>
#include <iterator> //迭代器头文件
#include <algorithm> //泛型算法头文件
using namespace std;
int main()
{
//使用库中的 vector
int arr[] = {1,24,62,63,3,34,85,32};
int len = sizeof(arr) / sizeof(arr[0]);
vector<int> vec(arr,arr + len);//用数组的区间、系统中的 vector 构造 vec 对象
cout << vec.size() << endl;//容器当前大小
cout << vec.max_size() << endl;//容器最大的可以存储的元素 这个数目与平台和实现相关,在我的机器上vector<int>的max_size为1073741823,而string的max_size为4294967294
vec[0] = 222; //将第一个元素改为222 针对 vec 来说是容器对象,对象怎么能用下标来做,证明在库中实现了中括号运算符的重载函数
vec.push_back(20);//尾插
vec.insert(vec.begin(),30);//按开始位置插
vector<int>::iterator index1 = find(vec.begin(),vec.end(),62);//按元素位置插
vec.insert(index1,66);
vec.pop_back();//尾删
vec.erase(vec.begin());//按开始位置删
vector<int>::iterator index2 = find(vec.begin(),vec.end(),85);//按元素位置删除
vec.erase(index2);
迭代器:面向对象的指针
针对容器对象内部数据,迭代器将其屏蔽起来。外部使用时,不能用一个普通指针指向内部空间。遍历整个元素时,通过迭代器的方式,给出一种遍历容器的方法。迭代器是面向对象的指针,拿不到内部的东西,需要容器返回一个区间出来(返回起始位置的迭代器:begin() 末尾位置迭代器:end() )。通过容器接口 begin() 和 end() 确定容器区间,从 begin 到 end 遍历一遍,就把所以数据遍历了。迭代器区间是半开半闭的区间,对于普通正向迭代器,针对 begin() 返回的就是起始位置(闭区间)元素迭代器,指向第一个元素,而 end() 返回最后一个元素后继位置(开区间)
//迭代器的打印
vector<int>::iterator it = vec.begin();//定义一个迭代器的对象 it ,指向起始位置元素
for(it;it != vec.end();it++)
{
cout << *it << " ";//it 可以解引用,实现了解引用运算符的重载函数 指针都可以解引用,迭代器是面向对象的指针
}
cout << endl;
return 0;
}
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;
template<typename T>
class MyVector
{
public:
typedef T value_type;//把T类型定义为值类型
//针对所有的容器,都有默认的构造函数,即不带参数的构造函数
MyVector()
{
//cursize = totalsize = 0;
arr = new T[1];
cursize = 0;
totalsize = 1;
}
~MyVector()
{
delete[] arr;//如果调用默认(无参数)构造函数,里面的 arr 没有任何处理,指向0XCCCC,delete导致程序奔溃
//为了统一资源释放,不用判断,在开始的时候,开辟一个字节
}
MyVector(int size)//可以用一个整型参数构造函数来构造容器对象 size代表元素的多少,比如传入20,就表示开辟20个大小的数组并初始化为0
{
if(size < 0)
return;
arr = new T[size]();
cursize = size;
totalsize = size;
}
MyVector(const MyVector<T>& rhs)//实现有指针拷贝构造函数,如果不写,使用系统提供的拷贝构造函数,是以一个浅拷贝,导致析构时同一块内存析构两次。所以要实现自己的深拷贝
{
arr = new T[rhs.totalsize]();//开辟空间
memcpy(arr,rhs.arr,sizeof(T)*rhs.cursize);//内容拷贝函数
cursize = rhs.cursize;
totalsize = rhs.totalsize;
}
MyVector<T>& operator = (const MyVector<T>&rhs)//实现 赋值运算符的重载函数
{
if(this != &rhs)//判断自赋值
{
delete[] arr;//释放旧空间
arr = new T[rhs.totalsize]();//开辟新空间
memcpy(arr,rhs.arr,sizeof(T)*rhs.cursize);
cursize = rhs.cursize;
totalsize = rhs.totalsize;
}
return *this;//命中自赋值返回
}
typedef Iterator<MyVector<T>> iterator;//传的应是容器类型
iterator begin()
{
return iterator(this,0);
}
iterator end()
{
return iterator(this,cursize);
}
T& operator[](int index)//在容器中实现 中括号运算符重载函数
{
return arr[index];
}
// vector 是矢量容器(一端增长),肯定要支持 push 操作,只有尾部插入 即 push_back
void push_back(T val)//相当于底层调用 Insert ,迭代器是尾部迭代器
{
Insert(end(),val);
}
void Insert(iterator _where,T val)//按当前迭代器的位置插入元素 Iterator _where:迭代器位置 T* val:元素
//怎么做可以在当前迭代器的位置插入元素? 按位置插入,肯定有数组的移动。
//怎么移动数组,从后面把元素依次挪一下,挪到一定位置时,刚好到迭代器位置
//问题:在迭代器里面取不到pos 不能将迭代器类型转为内置类型,能否将内置类型转为迭代器类型?
//可以
{
//插入时先判满,满的话扩容
if(IsFull())
{
resize();
}
iterator last = end();//定义一个迭代器 last 指向末尾
int pos = cursize;
while(last != _where)
{
arr[pos] = arr[pos - 1];
last--;
pos--;
}
arr[pos] = val;
cursize++;
}
// vector 删除
void pop_back1()// vector 尾删
{
Delete(end());//直接调用 Delete
}
void pop_back2()// vector 尾删
{
if(IsEmpty())
{
throw exception("vector is null");//为空抛出异常
}
cursize--;//将数组当前大小--
}
void Delete(iterator _where)// vector 任意位置的删除
{
if(IsEmpty())
{
throw exception("vector is null");//为空抛出异常
}
iterator first = begin();
int pos = 0;
while(first != _where)
{
first++;
pos++;
}
for(;pos < cursize;pos++)
{
arr[pos] = arr[pos + 1];
}
cursize--;
}
int size()//容器当前大小
{
return cursize;
}
void resize(int size = 0)//扩容
{
if(size == 0)
{
size = totalsize * 2;
}
T* newarr = new T[size];//开辟新空间
memcpy(newarr,arr,sizeof(T)*cursize);//memcpy 初始化
delete[] arr;//释放旧空间
arr = newarr;//旧空间等于新空间
totalsize = size;
}
void show()
{
for(int i = 0;i < cursize;i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
private:
T *arr;
int cursize;//数组当前大小
int totalsize;//数组总大小
bool IsFull()//判满
{
return cursize == totalsize;
}
bool IsEmpty()//判空
{
return cursize == 0;
}
};
template<typename Container>//迭代器是面向对象的指针,所以模板类型参数是容器类型
class Iterator
{
public:
Iterator(Container* vec,int index)//迭代器的构造
:pvec(vec),pos(index)
{}
//1 迭代器对象的实现
//1.1 比较运算法重载函数(比较迭代器不同代表的是元素位置不同,如何判断? 比较 pos 是否相同)
bool operator != (const Iterator& rhs)
{
return pos != rhs.pos;
}
//1.2 ++运算符重载函数(前置和后置)
//返回迭代器的引用
Iterator<Container>& operator++()//前置++
{
++pos;
return *this;
}
Iterator<Container>& operator++(int)//后置++
{
pos++;
return *this;
}
//针对 vector 是随机访问迭代器,既支持迭代器++,又支持迭代器--
Iterator<Container>& operator--()
{
--pos;
return *this;
}
Iterator<Container>& operator--(int)
{
pos--;
return *this;
}
//1.3 解引用运算符重载函数
//返回的是值类型的引用 Container是容器类型,要的是值类型,在vector容器中,对于每个值类型都会重定义的
//Container是容器,是类,类里面包含类型 直接用类里面的值类型value_type
typename Container::value_type& operator*()
{
return (*pvec)[pos];//pvec:容器对象的指针 *pvec:解引用变成容器对象 (*pvec)[pos]:pvec对象调用中括号运算符重载函数
//pevc->operator[](pos); pvec 调用 operator 中括号运算符重载函数,将 pos 传进去
}
//对于迭代器来说,是一个指针指向,对于是不是堆内存不关心,不用析构函数
private:
Container* pvec;//最后用 MyVector 这个类型来实例化 Container ,这个模板类型参数被替换成 MyVector* pvec, pvec 是容器对象的指针,也就是面向对象的指针,整个类都是面向对象的指针
//思考:迭代器指向某一个容器,怎样区分每个元素? 比如MyVector 生成 vec1 对象,拿 pvec 指向 vec1 对象,怎样区分 vector 里面每个元素?
//vector 是矢量容器,底层是数组,可以用下标区分每个元素
int pos;
};
int main()
{
//使用自己的 vector
MyVector<int> vec(1);
vec[0] = 10;
vec.Insert(vec.begin(),20);
vec.push_back(30);
vec.show();
vec.Delete(vec.begin());
vec.show();
vec.pop_back1();
vec.show();
//迭代器的打印
MyVector<int>::iterator it = vec.begin();
for(it;it != vec.end();it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
标签:容器,arr,顺序,迭代,pos,cursize,vector,vec 来源: https://blog.csdn.net/TUJI67/article/details/89606923