仿写vector类
来源:互联网 发布:视频大数据什么意思 编辑:程序博客网 时间:2024/04/29 12:23
前言
vector是C++ STL 中的一种数据结构,可以理解为“向量”或者是“可变长数组”。vector比普通的数组更加节省空间,但是它的时间效率显然不如普通的数组。我曾经听学长说vector 的push_back 操作的总复杂度为O(NlogN),但我不这么认为(或许是我得了幻听,没有学长说过这话)。为此我按照类似vector的原理仿写了一个简易的“vector类”。
代码
#include<stdlib.h>#include<string.h>namespace std{ template<class VarType>class vector //try to write a "vector" myslef { //made by NEYC GGN -2017.9.2, for study only //only has "some basic functions" of STL"vector" int len,siz; //len: the length of memory, siz: the amount of elments VarType* bgn; //the head of the array void swap(VarType*& A,VarType*& B){ VarType* t; t=A;A=B;B=t; //swap two pointer } public: vector(int Len=1){ //constructor siz=0;len=Len; //at first, len= basic Length bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } ~vector(){ //destructor free(bgn); //free the memory when delete the whole vector } void clear(){ free(bgn); //free the last array siz=0;len=1; //set len= 1 bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } int push_back(VarType itm){ //add an element at back if(!(siz<len)){ //if the vector is full len<<=1; //double the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } bgn[siz]=itm; //add an element return ++siz; //return the size of elements } int pop_back(){ //delete an element at back if(siz==0)return 0; //siz=0 can not pop_back if(siz<=(len>>1)){ //if can delete right half len>>=1; //decline the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } return --siz; } VarType* begin(){ //return head pointer return bgn; } VarType* end(){ //return tail pointer return bgn+siz; //vector => [ vec.begin(), vec.end() ) } VarType& operator[](int index){ //index a position in vector return bgn[index]; //attention! 0 <= index < vec.size() } int size(){ //return the count of elements invector return siz; //return "siz" }// int length(){ //get the length of the vector// return len; //for debug only, return len// } };}//test part of the algorithm:#include<cstdio>#include<algorithm>using namespace std;int main() //debug my vector's function{ vector<int>vec; //define a vector (as STL) printf("input n=? "); //input the siz of elements int n;scanf("%d",&n); printf("input array[0..%d]=? ",n-1); for(int i=1;i<=n;i++){ //input all the elements int a;scanf("%d",&a); vec.push_back(a); //push_back an element } sort(vec.begin(),vec.end()); //sort the vector for(int i=0;i<vec.size();i++) //output sorted vector printf("%d ",vec[i]); printf("\n"); while(vec.size()!=0){ //pop the whole vector vec.pop_back(); //attention! do not use the method to clear printf("siz=%d \n",vec.size()); } //if you want to clear, use "vec.clear()" return 0; //debug end}
这里再给出一个具有错误输出的debug_vector类和vector类的完整代码,便于调试。
#include<stdlib.h>#include<stdio.h>#include<string.h>namespace std{ template<class VarType>class vector //try to write a "vector" myslef { //made by NEYC GGN -2017.9.2, for study only //only has "some basic functions" of STL"vector" int len,siz; //len: the length of memory, siz: the amount of elments VarType* bgn; //the head of the array void swap(VarType*& A,VarType*& B){ VarType* t; t=A;A=B;B=t; //swap two pointer } public: vector(int Len=1){ //constructor siz=0;len=Len; //at first, len= basic Length bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } ~vector(){ //destructor free(bgn); //free the memory when delete the whole vector } void clear(){ free(bgn); //free the last array siz=0;len=1; //set len= 1 bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } int push_back(VarType itm){ //add an element at back if(!(siz<len)){ //if the vector is full len<<=1; //double the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } bgn[siz]=itm; //add an element return ++siz; //return the size of elements } int pop_back(){ //delete an element at back if(siz==0)return 0; //siz=0 can not pop_back if(siz<=(len>>1)){ //if can delete right half len>>=1; //decline the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } return --siz; } VarType* begin(){ //return head pointer return bgn; } VarType* end(){ //return tail pointer return bgn+siz; //vector => [ vec.begin(), vec.end() ) } VarType& operator[](int index){ //index a position in vector return bgn[index]; //attention! 0 <= index < vec.size() } int size(){ //return the count of elements invector return siz; //return "siz" }// int length(){ //get the length of the vector// return len; //for debug only, return len// } }; template<class VarType>class debug_vector //a vector with debug function { //made by NEYC GGN -2017.9.3, for study only //only has "some basic functions" of STL"vector" (with debug output) int len,siz; //len: the length of memory, siz: the amount of elments VarType* bgn; //the head of the array void swap(VarType*& A,VarType*& B){ VarType* t; t=A;A=B;B=t; //swap two pointer } public: debug_vector(int Len=1){ //constructor if(Len<=0){ fprintf(stderr,"Error:(constructor)the length of vector must >= 1!\n"); system("pause>nul");return; } siz=0;len=Len; //at first, len= basic Length bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } ~debug_vector(){ //destructor free(bgn); //free the memory when delete the whole vector } void clear(){ free(bgn); //free the last array siz=0;len=1; //set len= 1 bgn=(VarType*)calloc(len,sizeof(VarType)); //calloc new memory } int push_back(VarType itm){ //add an element at back if(!(siz<len)){ //if the vector is full len<<=1; //double the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array if(new_s==NULL){ fprintf(stderr,"Error:(push_back)can not calloc new memory!\n"); system("pause>nul");return siz; } memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } bgn[siz]=itm; //add an element return ++siz; //return the size of elements } int pop_back(){ //delete an element at back if(siz<=0){ //siz=0 can not pop_back fprintf(stderr,"Error:(pop_back)size of vector <=0!\n"); system("pause>nul");return siz; } if(siz<=(len>>1)){ //if can delete right half len>>=1; //decline the length of array VarType* new_s=(VarType*)calloc(len,sizeof(VarType)); //calloc new array memcpy(new_s,bgn,sizeof(VarType)*siz); //copy the elments before swap(new_s,bgn);free(new_s); //free the last array } return --siz; } VarType* begin(){ //return head pointer return bgn; } VarType* end(){ //return tail pointer return bgn+siz; //vector => [ vec.begin(), vec.end() ) } VarType& operator[](int index){ //index a position in vector if(index<0 || index>=siz){ fprintf(stderr,"Error:(operator[])index(=%d) must in [1,siz(=%d)-1]!\n",index,siz); system("pause>nul");return bgn[0]; } return bgn[index]; //attention! 0 <= index < vec.size() } int size(){ //return the count of elements invector return siz; //return "siz" } int length(){ //get the length of the vector return len; //for debug only, return len } };}
分析
上文代码的实现原理:
push_back:如果当前元素个数小于数组长度,直接插入这个元素;否则,重新申请一个长度为原数组长度二倍的数组,并把前面的元素复制到新数组中,再插入这个元素。
pop_back:如果当前元素个数小于数组长度的二分之一,可以申请一个长度为当前数组长度二分之一的数组,并把前面的元素复制过来,再删除当前元素;否则,直接删除当前元素。
假设calloc函数申请内存的时间复杂度为O(1)(实际上也是非常快的)。那么我们可以去估计一下插入N个数的时间复杂度:
(1)如果N=2^b (b为整数,b>1),那么需要花费时间代价
T=插入次数+sum(每次复制的长度)即:T=2^b+2^(b-1)+2^(b-2)+..+2^1+2^0=2^b+2^b-1=2N-1。因为在插入最后一个数的时候并没有超出2^n的限制,所以只需要从2^(b-1)加到2^1。(2)如果N=2^b+1
(b为整数,b>1),那么T=(2^b+1)+2^b+2^(b-1)+…+2^1+2^0=2^b+1+2^(b+1)-1=3*2^b=3N-3(3)除上面两种情况的N外,不难证明: T一定在2N-1到3N-3之间。
从以上三条来看,push_back N个数的总复杂度是O(N),均摊复杂度为插入一个数O(1)(注意是均摊),均摊复杂度常数大概是普通数组直接操作的三倍(或以上),理论占用空间不超过数组的二倍,所以空间复杂度也是O(N)。
pop_back也是同理,在此不进行证明。
这个时间复杂度针对的是你一直push-back或pop-back。如果你反复push一次pop一次,最后导致数组来回被复制,那复杂度就没有保证了。
后记
STL(Standard Template Library)为我们提供了很多很优秀的数据结构和算法模板,虽然可以直接使用,但我还是觉得应该了解一下各种STL的实现原理(意思就是不一定要会写,但是要“了解”)。
(比如说什么“set”“map”这种用红黑树实现的算法,自己手写的确是丧心病狂!!)
上文中仿写的vector的算法并不一定就是真正STL vector中的写法,但我觉得原理应该是类似的。
- 仿写vector类
- 仿C++ STL vector
- 仿Petshop写的数据库操作类
- 写一个仿string的类
- 仿写Scanner类的功能代码
- 常用string类函数仿写
- 写模板--Smarty类的编译功能仿写
- vector (仿sgi stl)
- 仿写cp命令
- java仿写计算器
- 古文仿写:桂娘传
- wxpython仿写记事本
- 仿写strcmp函数
- 仿写jquery
- ActionSheetDialog仿写
- 仿写礼物说
- 仿写 Lite Struts
- java仿写ArrayList
- CF848,第一次参加div1
- 移动端h5页面点透问题
- Linux 环境下使用g++编译C++
- 封装_练习
- java 字符的解码和编码
- 仿写vector类
- WOJ1092-Pure numbers
- (五)Saving Data保存数据
- 题目:一个数如果恰好等于它的因子之和,这个数被成为“完数”,例如:6=1+2+3。请编程找出1000以内的完数。
- linux 队列 C实现
- CentOS 7 网络配置
- 华为笔试题(1)
- linux 常用命令功能介绍
- 斐波那契数列(不使用递归的快速算法)