后台开发:核心技术与应用实践3.3.4 Vector类的简单实现

    xiaoxiao2024-01-09  179

    3.3.4 Vector类的简单实现

    实现一个vector,绝对是C++中的重点知识。下面例3.13中提供了类的简单实现。

    【例3.17】 vector类的简单实现。

    #include<algorithm>

    #include<iostream>

    #include <assert.h>

    using namespace std;

    template<typename T>

    class myVector

    {

    private:

        /*walk length*/

        /*myVector each time increase space length*/

        #define WALK_LENGTH 64;

     

    public:

        /*default constructor*/

        myVector():array(0),theSize(0),theCapacity(0){    }

        myVector(const T& t,unsigned int n):array(0),theSize(0),theCapacity(0){

            while(n--){

                push_back(t);

            }

        }

     

        /*copy constructor*/

        myVector(const myVector<T>& other):array(0),theSize(0),theCapacity(0){

            *this = other;

        }

     

        /*= operator*/

        myVector<T>& operator =(myVector<T>& other){

            if(this == &other)

                return *this;

            clear();

            theSize = other.size();

            theCapacity = other.capacity();

            array = new T[theCapacity];

            for(unsigned int i = 0 ;i<theSize;++i)

            {

                array[i] = other[i];

            }

            return *this;

        }

     

        /*destructor*/

        ~myVector(){

            clear();

        }

     

        /*the pos must be less than myVector.size();*/

        T& operator[](unsigned int pos){

            assert(pos<theSize);

            return array[pos];

        }

     

        /*element theSize*/

        unsigned int size(){

            return theSize;

        }

     

        /*alloc theSize*/

        unsigned int capacity(){

            return theCapacity;

        }

     

        /*is  empty*/

        bool empty(){

            return theSize == 0;

        }

     

        /*clear myVector*/

        void clear(){

            deallocator(array);

            array = 0;

            theSize = 0;

            theCapacity = 0;

        }

     

        /*adds an element in the back of myVector*/

        void push_back(const T& t){

            insert_after(theSize-1,t);

        }

     

        /*adds an element int the front of myVector*/

        void push_front(const T& t){

            insert_before(0,t);

        }

     

        /*inserts an element after the pos*/

        /*the pos must be in [0,theSize);*/

        void insert_after(int pos,const T& t){

            insert_before(pos+1,t);

        }

     

        /*inserts an element before the pos*/

        /*the pos must be less than the myVector.size()*/

        void insert_before(int pos,const T& t){

            if(theSize==theCapacity){

                T* oldArray = array;

                theCapacity += WALK_LENGTH;

                array = allocator(theCapacity);

                /*memcpy(array,oldArray,theSize*sizeof(T)):*/

                for(unsigned int i = 0 ;i<theSize;++i){

                    array[i] = oldArray[i];

                }

                deallocator(oldArray);

            }

     

            for(int i = (int)theSize++;i>pos;--i){

                array[i] = array[i-1];

            }

            array[pos] = t;

        }

     

        /*erases an element in the pos;*/

        /*pos must be in [0,theSize);*/

        void erase(unsigned int pos){

            if(pos<theSize){

                --theSize;

                for(unsigned int i = pos;i<theSize;++i){

                    array[i] = array[i+1];

                }

            }

        }

     

    private:

        T*  allocator(unsigned int size){

            return new T[size];

        }

     

        void deallocator(T* arr){

            if(arr)

                delete[] arr;

        }

    private:

        T*                                array;

        unsigned int    theSize;

        unsigned int    theCapacity;

    };

     

    void printfVector(myVector<int>& vector1){

        for(unsigned int i = 0 ; i < vector1.size();++i){

            cout<<vector1[i]<<",";

        }

        cout<<"alloc size = "<<vector1.capacity()<<",size = "<<vector1.size()<<endl;

    }

     

    int main(){

        myVector<int> myVector1;

        myVector<int> myVector2(0,10);

        myVector2.push_front(1);

        myVector2.erase(11);

        printfVector(myVector2);

        myVector1.push_back(2);

        myVector1.push_front(1);

        printfVector(myVector1);

        myVector1.insert_after(1,3);

        printfVector(myVector1);

     

        myVector2 = myVector1;

        myVector2.insert_before(0,0);

        myVector2.insert_before(1,-1);

        printfVector(myVector2);

        return 0;

    }

    程序的执行结果为:

    1,0,0,0,0,0,0,0,0,0,0,alloc size = 64,size = 11

    1,2,alloc size = 64,size = 2

    1,2,3,alloc size = 64,size = 3

    0,-1,1,2,3,alloc size = 64,size = 5

    STL库中vector是一个自动管理的动态数组,只要明白vector的类型是一个数组,至于怎么去实现它其实不难。例3.17中选择了一种简单的方式去实现它:定义一个步长WALK_LENGTH,在数组空间不够时,再重新申请长度为theCapacity +WALK_LENGTH的内存,这样就避免了每次当myVector元素增加的时候,需要去重新申请空间的问题,当然不好的地方就是会浪费一定的空间,但是时间效率上会提高很多。因为vector可以支持下标访问,所以就不用单独构造一个iterator,从而提高效率。

    例3.17中,myVector拥有3个成员变量:元素的个数theSize、容量theCapacity和一个指针数组array。

    默认构造函数里,把元素的个数theSize、容量theCapacity都赋值为0,数组赋值为空,代码如下:

    myVector():array(0),theSize(0),theCapacity(0){    }

    用几个相同的值赋值给myVector,那应该是逐个添加的:

        myVector(const T& t,unsigned int n):array(0),theSize(0),theCapacity(0){

            while(n--){

                push_back(t);

            }

        }

    进行重载:

        myVector<T>& operator =(myVector<T>& other){

            if(this == &other)

                return *this;

            clear();

            theSize = other.size();

            theCapacity = other.capacity();

            array = new T[theCapacity];

            for(unsigned int i = 0 ;i<theSize;++i)

            {

                array[i] = other[i];

            }

            return *this;

        }

    如果参数与本myVector相同,那就无需赋值了;不相同时才需要赋值,并需要分别对3个成本变量进行赋值,元素个数、容量大小和数组内容。

    析构函数里直接调用clear函数,如下所示:

        ~myVector(){

            clear();

        }

    用下标的方式访问myVector中的元素,其实就是访问数组array中的元素,注意下标必须小于元素个数,如下所示:

        T& operator[](unsigned int pos){

            assert(pos<theSize);

            return array[pos];

        }

    获得元素个数和容器大小,直接返回成员变量即可,如下所示:

        /*element theSize*/

        unsigned int size(){

            return theSize;

        }

     

        /*alloc theSize*/

        unsigned int capacity(){

            return theCapacity;

        }

    判断myVector是否为空,直接判断元素个数是否等于0即可,如下所示:

        bool empty(){

            return theSize == 0;

        }

    清空myVector中的元素,需要删除掉数组指针,并把元素个数和容量大小都置0,如下所示:

        void clear(){

            deallocator(array);

            array = 0;

            theSize = 0;

            theCapacity = 0;

        }

    push_back、push_front都可以归根于insert,在哪个位置插入,如下所示:

        void push_back(const T& t){

            insert_after(theSize-1,t);

        }

     

        void push_front(const T& t){

            insert_before(0,t);

        }

     

        void insert_after(int pos,const T& t){

            insert_before(pos+1,t);

        }

     

        void insert_before(int pos,const T& t){

            if(theSize==theCapacity){

                T* oldArray = array;

                theCapacity += WALK_LENGTH;

                array = allocator(theCapacity);

                /*memcpy(array,oldArray,theSize*sizeof(T)):*/

                for(unsigned int i = 0 ;i<theSize;++i){

                    array[i] = oldArray[i];

                }

                deallocator(oldArray);

        }

     

            for(int i = (int)theSize++;i>pos;--i){

                array[i] = array[i-1];

            }

            array[pos] = t;

    }

    myVector通过一个连续的数组存放元素,如果集合已满,在新增数据的时候,就要分配一块更大的内存,将原来的数据复制过来,释放之前的内存,再插入新增的元素。这个元素后面的所有元素都向后移动一个位置,在空出来的位置上存入新增的元素。

    删除某个元素,则要把这个元素后面的都往前挪,并把元素个数-1,如下所示:

    void erase(unsigned int pos){

        if(pos<theSize){

            --theSize;

            for(unsigned int i = pos;i<theSize;++i){

                array[i] = array[i+1];

            }

        }

    }

    通过分析代码,可以发现vector的特点,如下所述。

    (1)随即访问元素效率很高。

    (2)push_back的效率也会很高。

    (3)push_front的效率非常低,不建议使用。

    (4)insert需要把插入位置以后的元素全部后移,效率比较低,不建议使用。

    (5)erase需要把删除位置后面的元素全部前移,效率比较低,不建议使用。

    (6)当内存不够时,需要重新申请内存,再把以前的元素复制过来,效率也比较低。

    3.4 map

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)