C++数据结构:Vector的实现(完结)

一、什么是vector?

向量vector是C++中最常用的STL之一,它的优点在于:

  1. 动态大小,不像数组一般大小固定
  2. 可以很高效的在它尾部进行元素的增删
  3. 快速随机访问
  4. 支持迭代器
  5. 内存连续
    这篇文章我们将动手实现一个简单的vector,在提升C++代码能力的同时理解为什么vector具有这些特点。
    PS:由于水平等总总原因,有的方法我没法一次性实现,故这篇文章内容将不断更新完善,望谅解,也希望大家能指出这篇文章的不足和错误

二、需要实现的操作介绍

函数名称实现的操作
push_back(num)在vector的尾部增加元素num
size()返回vector的大小
binary_search()二分查找,找出第一次出现的指定元素
[ ]使得vector能像数组一样进行快速的下标访问
shrink()范围缩小函数,避免浪费内存
bubble_sort()冒泡排序

三、目前已经实现的操作

  1. push_back()
  2. size()
  3. [ ]
  4. binary_search();
  5. bubble_sort()
  6. shrink()

四、完整代码

//避免重复定义
#ifndef VECTOR_CPP
#define VECTOR_CPP

#define MINSIZE 3

template <typename T>
class Vector{
public:
    Vector();
    Vector(const Vector<T>&);
    ~Vector();

    T operator[](int index);

    int size();
    void push_back(T value);
    void shrink();

    //选择排序函数
    void sort(int value);
    
    //二分查找1
    int binary_search(T value);

    //冒泡排序1
    void bubble_sort();
private:
    int sizeVal = 0;
    //元素容量
    int length = MINSIZE;
    //数组规模
    T* arr;
    //空间
};

template<class T>
Vector<T>::Vector(){
    arr = new T[length];
}

template <class T>
Vector<T>::Vector(const Vector<T>& temp){
    this->length = temp.length;
    this->sizeVal = temp.sizeVal;
    this->arr = new T[length];
    for(int i=0;i<this->sizeVal;i++){
        this->arr[i] = temp.arr[i];
    }
}

template<class T>
Vector<T>::~Vector(){
    delete[] arr;
}

template<class T>
T Vector<T>::operator[](int index){
    return this->arr[index];
}

template<class T>
int Vector<T>::size(){
    return this->sizeVal;
}

template<class T>
void Vector<T>::push_back(T value){
    this->sizeVal++;
    if(sizeVal>length){
        int* newArr = arr;
        this->length *= 2;
        arr = new int[length];
        for(int i=0;i<sizeVal-1;i++){
            arr[i]=newArr[i];
        }
        arr[sizeVal-1]=value;
        delete[] newArr;
    }
    else{
        arr[sizeVal-1]=value;
    }
}

template<class T>
void Vector<T>::shrink(){
    T* newArr = new T[sizeVal];
    for(int num=0;num<sizeVal;num++){
        std::swap(neaArr[num],this->arr[num]);
    }
    delete[] this->arr;
    this->arr=newArr;
}

template<class T>
void Vector<T>::sort(int value){
    switch (value)
    {
    case 1:
        this->bubble_sort();
        break;
    
    default:
        break;
    }
}

template<class T>
//优化二分查找
int Vector<T>::binary_search(T value){
    //无重复有序,中间值
    int low=0,high=this->sizeVal-1;
    while(low<high){
        int mid=(low+high)>>1;
        if(value<this->arr[mid]){
            high=mid-1;
        }
        else if(value>arr[mid]){
            low=mid+1;
        }
        else if(value==arr[mid]){
            return mid;
        }
    }
    return -1;
}


template<class T>
void Vector<T>::bubble_sort(){
    //sizeVal是元素个数
    //冒泡
    for(int i=0;i<this->sizeVal;i++){
        for(int j=i;j<this->sizeVal;j++){
            if(arr[i]>arr[j]){
                int temp=arr[j];
                arr[j]=arr[i];
                arr[i]=temp;
            }
        }
    }
}



#endif

五、代码逐步实现

(1) 声明Vector类

这一步声明Vector和要实现的函数,由于vector是一个模板类,所以我们也运用C++的模板来进行实现

#define MINSIZE 3//向量最小的数据空间的大小

template<class T>
class Vector{
public:
	Vector();
	Vector(const Vector<T>& temp);
	~Vector();
	
	void push_back(T value);
	int size();//返回向量的大小

	T operator[](int index);
private:
	int sizeVal = 0;//向量的长度
	int length = MINSIZE;//向量的空间大小,MINSIZE为初始的最小空间
	int *arr;//向量的数据空间
};
(2) 定义Vector的构造函数

我们先要明确在构造函数中,我们需要完成什么内容:给Vector分配一个初始的数据空间,这个数据空间不必太大,因为假如我们给的数据很小,但是我们却分配了大块空间,这会浪费内存,因此我们使用宏MINSIZE,定义了Vector的初始最小内存空间,并使用它初始化length

template<class T>
Vector<T>::Vector(){
	arr = new T[length];
}
(3) 定义Vector的拷贝构造函数

简单的赋值操作

template <class T>
Vector<T>::Vector(const Vector<T>& temp){
    this->length = temp.length;
    this->sizeVal = temp.sizeVal;
    this->arr = new T[length];
    for(int i=0;i<this->sizeVal;i++){
        this->arr[i] = temp.arr[i];
    }
}
(4) 定义Vector的析构函数

在Vector的析构函数中,我们需要释放之前分配的内存,来避免内存泄漏

template<class T>
Vector<T>::~Vector(){
	delete[] arr;
}
(5) 实现push_back()

这个函数的作用是在Vector的尾部增加元素。需要注意的是:它需要进行的不单是一个简单的增加,由于在添加之后,我们需要对其数据空间的大小进行判断,如果在元素插入之后数据空间所规定的大小已经不够用了,我们就需要对数据空间进行扩容处理

template<class T>
void Vector<T>::push_back(T value){
    this->sizeVal++;//先将元素个数增加

	//判断元素个数有没有超过数据空间的大小
	//如果超过了,空间大小翻倍
    if(sizeVal>length){
        int* newArr = arr;
        this->lenght *= 2;

		//分配一个新的、更大的空间
        arr = new int[length];

		//将原来的元素复制
        for(int i=0;i<sizeVal-1;i++){
            arr[i]=newArr[i];
        }

		//添加元素
        arr[sizeVal-1]=value;
        delete[] newArr;
    }

	//如果空间足够,直接添加
    else{
        arr[sizeVal-1]=value;
    }
}

相信理解了这个步骤之后也就明白了为什么vector的迭代器在vector进行了改变之后可能失效了,因为在插入元素后可能因为扩容使得数据空间的位置发生了改变,原来的迭代器指向的内存被释放,也就无效了

(6) 实现size()

这个函数是最简单的一个了,因为我们在定义的时候就已经使用了一个变量sizeVal来储存其元素个数:

template<class T>
int Vector<int>::size(){
	return this->sizeVal;
}
(7) 重载下标运算符

这一步使得vector能够像数组一样进行下标访问,也没什么难度。

template<class T>
T Vector<T>::operator[](int index){
    return this->arr[index];
}
(8) 实现binary_search()函数

这个函数使用的是二分查找,但是由于是要找到这个元素第一次出现的位置,所以是一个二分查找的边界查找

template<class T>
//优化二分查找
int Vector<T>::binary_search(T value){
    int low=0,high=this->sizeVal-1;
    while(low<high){
        int mid=(low+high)>>1;
        if(value<this->arr[mid]){
            high=mid-1;
        }
        else if(value>arr[mid]){
            low=mid+1;
        }
        else if(value==arr[mid]){
            return mid;
        }
    }
    return -1;
}
(9)实现bubble_sort()函数

这是最简单的排序方法,这个函数的增加只是为了掌握冒泡排序这个算法,但是由于这个算法的效率极低,通常是不会使用的。在数据量较大的时候,程序的运行时间就已经很长了。在后面还会有很多更好的排序算法。

template<class T>
void Vector<T>::bubble_sort(){
    //sizeVal是元素个数
    //冒泡
    for(int i=0;i<this->sizeVal;i++){
        for(int j=i;j<this->sizeVal;j++){
            if(arr[i]>arr[j]){
                int temp=arr[j];
                arr[j]=arr[i];
                arr[i]=temp;
            }
        }
    }
}
(10)实现shrink函数

这个函数起到容器的缩容作用,就是说在停止输入之后,我们需要调用这个函数,删除分配了空间但是没有储存元素的部分,避免内存的浪费。但是由于我这个Vector在设计的时候没有设计好,这个需要我们在结束了push_back()之后进行手动调用,实际上vector的调用形式比我的聪明多了:

template<class T>
void Vector<T>::shrink(){
    T* newArr = new T[sizeVal];
    for(int num=0;num<sizeVal;num++){
        std::swap(neaArr[num],this->arr[num]);
        //利用交换,提高效率
    }
    delete[] this->arr;
    this->arr=newArr;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

默示MoS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值