C++动态数组的简易实现

​ 在啃过 STL源码剖析的vector这一章后,我准备自己写一个动态数组。因为在STL中的vector为了防止频繁的发生,添加元素->配置空间->移动元素->释放原空间,于是采用类似缓冲池的技术,减少空间配置的次数。这个技术就是 size + capacity 。下面举个例子,假如我们正常使用动态数组怎么改变

//使用动态数组的步骤int* iptr = new int[10];//插入元素 1
//1、创建新空间
int* tmp = new int[11];
//2、将旧元素移到新空间
for(int i=0;i<10;++i)tmp[i] = iptr[i];
//3、插入元素赋值
tmp[10]=1;//4、释放旧元素
delete[] iptr;//5、改变指向
iptr = tmp;

​ 可以看到我们繁琐的步骤,导致每插入一个元素就要进行一次内存配置操作,非常的麻烦,且进行一次malloc代价很大。这个效果在数组越大的时候体现的越明显。这个时候STL就引入了容量(预备空间)来作为缓冲区,其实也就是一个预备空间。只有当我们预备空间满了才会进行元素拷贝和移动。

​ ps:STL中 vector 有空间配置器,底层使用的是realloc、memcpy、placement-new ,所以较之于我自己实现的版本效率更高,同时可以减少元素移动的频率,只有realloc调用失败,才开始移动元素

​ 动态数组实现如下:

#define INITSIZE 8//要求数据元素是遵循严格弱序的
/*设计时,把错误处理留给调用者,在设计算法是不考虑外部的调用是否合理(如边界问题,由调用者处理)
*/
template<typename T>
class Vector
{
public:Vector();Vector(size_t, const T& tmp);~Vector();Vector<T>& operator=(const Vector& data);
public:size_t size() { return _size; };     //返回sizebool empty() { return !_size; };void clear();                   //清空//增删改查T& operator[](size_t index);  //改void push_back(T& data);     //增void push_back(T&& data);size_t earse(size_t indexl,size_t indexr);  //数组范围删除size_t insert(size_t index,const T& data);  //元素随机插入void pop();                     //删除尾部元素T& search(T& data);             //查:返回第一个匹配元素,方案二:区间范围查找实现全区间范围查找private:void expand();                    //扩张size_t _size;size_t _capacity;T* _array;            //底层数组};

容量扩张

​ 缓冲如何实现?就是通过容量,默认容量为8,容量就是底层数组实际大小,当添加元素导致容量满,就调用expand进行构造新空间,元素移动操作等

template<typename T>
void Vector<T>::expand()
{//1、创建新数组,新数组容量为原来的两倍,即数组下次扩张更加遥远。可以减少移动次数,但同时增加空间上的维护成本//解决方法有:实现一个缩容方法,一旦size和capacity相差过多,则进行缩容,如果底层是realloc实现效率更高T* tmp = new T[_capacity = _capacity << 1];for (int i = 0; i < _size; ++i) //把原数组中所有元素拷贝到新数组{tmp[i] = _array[i];}delete[]_array;_array = tmp;
}//提供一种实现,这个接口,只需要放在删除操作前
template<typename T>
void shink()
{if(_size-1 <= _capacity>>2)return;//否则缩容T* tmp = new T[_capacity = _capacity >> 1];  for (int i = 0; i < _size; ++i)   //把原数组中所有元素拷贝到新数组{tmp[i] = _array[i];}delete[]_array;_array = tmp;
}

插入操作

​ insert接口实现如下:

template<typename T>
size_t Vector<T>::insert(size_t index, const T& data)
{if (_size+1 >=_capacity) expand();    //如果容量不足for (int i = _size; i < index; --i){    _array[i] = _array[i - 1];}_array[index] = data;  //改变目标元素++_size;return index; //成功返回下标
}

删除

​ 删除操作也是一个亮点,这也是size + capacity 结构带来的好处。被删除元素完全不需要管理,直接覆盖掉,然后改变 size 即可。

template<typename T>
size_t Vector<T>::earse(size_t indexl, size_t indexr)
{if (indexl > indexr) return -1; //左下标小于右下标if (indexl >= _size && indexr >= _size) return -1;    //左、右下标不能等于数组大小//接下来就是不越界的情况//删除元素,采用吧后续元素前移的方法:时间复杂度为 o(n)、空间复杂度为 o(1);int n = 1 + indexr - indexl;while (indexl+n <_size){_array[indexl] = _array[indexl + n];}_size -= n;return indexl;   //返回删除元素第一个位置下标
}

​ ps:秉承oop思想,类似这种接口,底层都要有一个基础实现,比如push_bach、pop_back都是insert和earse的一个特化实现。所以想要仔细实现一个这样的接口一定要有一个泛化的接口,在简单转发一下成为多个特化的接口。

重载[ ]运算符

​ 重载下标运算符,是为了匹配使用习惯

template<typename T>
T& Vector<T>::operator[](size_t index)
{return _array[index];  //直接返回
}

查找

​ 这里就是应该实现一个 search(int start, int end, const T& data ); 这样一个接口,可以参考C++中的algorithm库,基本上都是基于一个范围操作接口,进行特化成不同接口。其实都是语法糖罢了。

//对于无序数组,只能遍历了。但是有序数组就有很多方法
template<typename T>
T& Vector<T>::search(T& data)
{for (int i = 0; i < _size; ++i)if (data == _array[i]) return _array[i];
}//可以提供一个快排的实现:但是我没有添加进入,因为我觉得动态数组不该内置这个接口
//排序也应该基于泛化的思想,实现一个区间排序
template<typename T>
void quicksort(T* array, size_t low, size_t high){if (low >= high) return;size_t i = low;size_t j = high;T key = array[i];while (i < j){while (i < j && array[j] >= key)   --j;if (i < j) array[i] = array[j];while (i < j && array[i] <= key) ++i;if (i < j)  array[j] = array[i];}array[i] = key;quicksort(array, low, i - 1);quicksort(array, i + 1, high);}

STL中的vector

​ 和我写的区别最大的地方就在于:1、使用了空间配置器;2、使用了迭代器。

​ STL中元素范围是以3个迭代器:

​ 使用迭代器可以支持许多算法,find、find_if、search、sort等。但是最大的作用还是对于边界的检查是便捷的。这就是迭代器使用是我们最常用的的一个条件 != end() ,有助于让我们拜托这该死的边界检查,和下标溢出。

template<class T, class Alloc=alloc>
class vector{
...
protected:iterator start;               //使用空间头iterator finish;         //使用空间尾iterator end_of_storage;  //未使用空间尾
}

​ STL中许多数据结构都值得我们学习。尤其是基础数据结构中一些理念和思想,可以很好的帮助我们解决一些边界问题,使用一点代价,就可以避免很多边界问题,哦,这也许就是编程的魅力。

C++动态数组的简易实现相关推荐

  1. js 多维数组长度_C++申请与释放动态数组1(学习笔记:第6章 16)

    分配和释放动态数组[1] 分配: new 类型名T [ 数组长度 ] 数组长度可以是任何表达式,在运行时计算 释放:delete[] 数组名p 释放指针p所指向的数组. p必须是用new分配得到的数组 ...

  2. vector,数组,动态数组效率测试

    对vector.数组.new创建的动态数组.预先reverse的vector测试代码如下: #include <iostream> #include <vector> #inc ...

  3. C++中关于[]静态数组和new分配的动态数组的区别分析

    一.静态数据及动态数组的创建 静态数据: int a[10]: int a[]={1,2,3}; 数组的长度必须为常量. 动态数组: int len; int *a=new int [len]; de ...

  4. 基础数据结构【二】————动态数组,单向链表及链表的反转

    DEMO1:     动态分配变量(链表,而静态数组是线性表,意味着动态数组访问和遍历复杂度为O(n),而插入和删除复杂度为O(1),而静态数组线性表则完全相反) int* intptr = new ...

  5. vector 容器 动态数组总结

    vector 容器 动态数组总结 二话不说直接上代码 #include <vector> #include <algorithm> #include <iostream& ...

  6. C++动态数组再总结

    动态数组是指在编译时不能确定数组长度,程序在运行时需要动态分配内存空间的数组. 1.变长一维数组 实现变长数组最简单的是变长一维数组,你可以这样做: //文件名:array01.cpp#include ...

  7. python动态数组的最大值_python实现动态数组的示例代码

    实现一个支持动态扩容的数组并完成其增删改查 #通过python实现动态数组 """ 数组特点: 占用一段连续的内存空间,支持随机(索引)访问,且时间复杂度为O(1) 添加 ...

  8. 【 C 】用动态数组实现堆栈

    上篇博文:[ C ]经典抽象数据类型(ADT)之堆栈(用静态数组实现堆栈)讲了堆栈的基础知识以及如何用静态数组实现堆栈. 这篇博文简单记录下用动态数组实现堆栈! 整体的实现过程和用静态数组实现堆栈相似 ...

  9. xcode新版本single view_动态数组函数系列1|概况-跟以往Excel版本完全不一样玩法的函数...

    早就听说在Office2019和Office365版本中增加了动态数组函数(Dynamic arrays),早前一直处于内测阶段,只对部分预览用户开放.昨天试了一下,我用的版本已经更新可用了.当前我使 ...

最新文章

  1. TCP的协议特点(对于《Linux高性能服务器编程》的部分摘录以及自己的部分见解)
  2. java response 对象_82 Java基础 Response对象
  3. 马尔科夫、最大熵、条件随机场
  4. linux sqlplus 密码有$
  5. 成功解决Remix Mock compiler: Source not found
  6. centos yum php apc,centos – PECL APC安装 – 错误:’make’失败
  7. [BZOJ2654] tree
  8. PHP读写操作Excel
  9. ffplay分析 (seek操作处理)
  10. MATLAB各类函数详细讲解 simulike系统仿真分析
  11. 如何通过Dataphin构建数据中台新增100万用户?
  12. linux与windows查看占用端口的进程ID并杀死进程
  13. 边工作边刷题:70天一遍leetcode: day 56-1
  14. java获取文件大小_Java获取文件大小
  15. 程序员应该具备的12种能力
  16. 淘宝客CMS,公众号,小程序,淘客APP,外卖返利系统
  17. OpenCV C++安装和配置
  18. 与你一起学习MS Project——基础篇:Project基础应用
  19. 小波 奇异点 matlab,用Matlab小波变换检测奇异点.doc
  20. PMP工作绩效数据、信息和报告三者的区别

热门文章

  1. python的高级应用
  2. 艺龙旅行闪退问题分析
  3. deepin20.4为绿色软件创建桌面图标
  4. emacs shell插件_非程序员的GNU Emacs使用心得...... 大话Emacs—Shell Mode
  5. 内存泄露与内存溢出的区别及解决方法
  6. Win7下vs2013打开鼠标不能用,鼠标失灵
  7. html5鼠标悬停提示框,HTML5鼠标悬停动画提示框特效源码,前端必备
  8. 模型涨点的思路,深度学习训练的tricks-计算机视觉
  9. 2022年最新河北水利水电施工安全员模拟试题题库及答案
  10. 微信小程序中转换时间格式IOS不兼容的问题