我造的轮子——山寨版vector

昨天看C++里面的容器部分,发现vector的特性很独特:

  • vector对于随机访问有很好的效率,猜想可能是顺序存储
  • vector对随机插入和删除的效率不高,这种特性也是由顺序存储引起的
  • vector容器的容量是自增长的,并不是一开始申请很大一块内存然后直到撑满,而是满了后容量加倍。

这种特性跟delphi的TList特别像,在delphi里面,放一个array of pointer的指针,

这个指针所指向的空间的内存是动态增长的,容量到达后就增加一个delta,它的增删改查,分别是这么实现的:

  • 增加分为两种情况:

(1)在末尾增加:首先判断容量满了没有,如果没有满则直接在数组后面赋值,如果满了就要增加容量后赋值

(2)在中间插入:首先要移出空位给需要insert的元素,然后赋值,移动之前要判断容量是否充足,++size

  • 删除:删除操作就是将要删除的元素后面的内存单元向前面移动一格,--size
  • 查,非常简单,只要index在范围内,直接用数组的index就可以查到元素,非常高效

我实现的代码基本上是仿照delphi的TList实现的,顺便加入了模板编程,插入的元素是泛型的。

这点较delphi有较大改进。delphi只支持管理pointer类型的。我插入的时候用的都是对象的副本,因为所有需要传元素

的地方都没有用引用,对于基本类型来说,空间损耗很小,但是对于对象来说有可能会空间损耗很大。

另外这个例子也没有实现delphi里面的notify机制,delphi考虑扩展性,加入了notify,方便派生类操作。

头文件:

我造的轮子——山寨版vector我造的轮子——山寨版vector头文件

#ifndef CLASSES_H #define CLASSES_Hconst int MAXCAPACITY = 100000;template <class Type>class my_vector{private:    typedef Type(*PType_Array)[MAXCAPACITY];    PType_Array data_list;    int    count;    int capacity;    void grow();public:    my_vector():count(0), capacity(0){}    ~my_vector(){clear();}    void set_Capacity(int cap);    int get_capacity();    void set_count(int count);    int get_count();    int add(Type t);    void clear();    void remove_by_index(int index);    void remove(Type t);    int index_of(Type t);    void insert(int index, Type t);    Type first();    Type last();    Type operator[](int i);};#endif

我造的轮子——山寨版vector我造的轮子——山寨版vector源文件

#include "stdafx.h"#include "classes.h"#include <cstdlib>template<class Type> void my_vector<Type>::grow(){    int delta;    if (capacity <= 8)        delta = 4;    else if (capacity <= 64)        delta = 16;    else        delta = capacity/4;    set_Capacity(capacity + delta);}template<class Type> void my_vector<Type>::set_Capacity(int new_capacity){    if (new_capacity<count || new_capacity>MAXCAPACITY){        std::cerr<<"Capacity Invalid"<<endl;        exit(0);    }    if(count == 0){        data_list = (PType_Array)malloc(sizeof(Type)*new_capacity);        capacity = new_capacity;    }    else if (new_capacity != capacity){        data_list = (PType_Array)realloc(data_list, sizeof(Type)*new_capacity);        capacity = new_capacity;    }}template<class Type> int my_vector<Type>::get_capacity(){    return capacity;}template<class Type> void my_vector<Type>::set_count(int new_count){    if (new_count<0 || new_count > MAXCAPACITY){        std::cerr<<"Capacity Invalid"<<endl;        exit(0);    }    if (new_count > capacity)        set_Capacity(new_count);    if (new_count > count)        memset((*data_list)+count, 0, sizeof(Type)*(new_count - count));    else{        int i=0;        for(i=count-1; i>=new_count; --i)            remove_by_index(i);    }    count = new_count;}template<class Type> int my_vector<Type>::get_count(){    return count;}template<class Type> void my_vector<Type>::remove(Type t){    int index = index_of(t);    if (index >= 0)        remove_by_index(index);}template<class Type> void my_vector<Type>::remove_by_index(int index){    if (index < 0 || index >= count)    {        std::cerr<<"out of bound"<<endl;        exit(0);    }    --count;    memcpy(*data_list + index, *data_list + index+1, (count-index)*sizeof(Type));}template<class Type> int my_vector<Type>::add(Type t){    int res;    res = count;    if (res == capacity)        grow();    (*data_list)[res] = t;    ++count;    return res;}template<class Type> void my_vector<Type>::insert(int index, Type t){    if(index < 0 || index > count){        std::cerr<<"out of bound"<<std::endl;        exit(0);    }    if (count == capacity)        grow();    memcpy((*data_list) + index + 1, (*data_list) + index, count-index);    (*data_list)[index] = t;    ++count;}template<class Type> Type my_vector<Type>::first(){    if (count > 0)        return (*data_list)[0];    else    {        cerr<<"no element"<<endl;        exit(0);    }}template<class Type> Type my_vector<Type>::last(){    if (count > 0)        return ((*data_list)[count - 1]);    else    {        cerr<<"no element"<<endl;        exit(0);    }}template<class Type> Type my_vector<Type>::operator[](int i){    if(i>=count || i<0){        cerr<<"No element"<<endl;        exit(0);    }    return (*data_list)[i];}template<class Type> void my_vector<Type>::clear(){    set_count(0);    set_Capacity(0);}template<class Type> int my_vector<Type>::index_of(Type t){    int i(-1), res(-1);    for (i = 0; i<count; ++i)    {        if((*data_list)[i] == t)        {            res = i;            break;        }    }    return res;}

我造的轮子——山寨版vector我造的轮子——山寨版vector主函数

#include "stdafx.h"#include "classes.cpp"#include "classes.h"#include <iostream>#include <string>using namespace std;void display_vector(my_vector<char*> vec){    int i;    for(i=0;i<vec.get_count();++i)        cout<<vec[i]<<" ";    cout<<endl;}int _tmain(int argc, _TCHAR* argv[]){    my_vector<char*> vec;    /////test add    for(int i = 0; i< 50; ++i){        char *str = new char[10];        sprintf(str, "%d", i);        vec.add(str);    }    ////test remove;    cout<<vec.get_count()<<endl;    vec.remove_by_index(5);    cout<<vec.get_count()<<endl;    ////test remove    cout<<vec.get_count()<<endl;    vec.remove(0);    cout<<vec.get_count()<<endl;    ////test insert;    vec.insert(12, "asss");    cout<<vec.get_count()<<endl;    vec.first();    vec.last();    display_vector(vec);}

另外关于泛型编程,要特别注意工程的链接方式,因为没有确定类型的时候,编译器不知道如何编译泛型函数,只有当确定类型后,

才会去找源文件。可以说泛型的编译是一种懒编译。

所以在用的时候要确保能链接到header对应的源文件。c++ primer里面用的是在header文件里面#include "xxxx.cpp"的方式

我用的这种方式比较挫一点,直接在主函数的cpp文件里 #include "xxx.cpp"的方式。
原文链接: https://www.cnblogs.com/lovelyxia/archive/2010/12/23/1915290.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/19178

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月7日 下午8:10
下一篇 2023年2月7日 下午8:11

相关推荐