vector容器

在标准容器中,只有vector和string提供了所有这些函数。

(1)size()可以获得容器中有多少元素,但不能获得容器为它容纳的元素分配的内存大小。
(2)capacity()可以获得容器在它已经分配的内存中可以容纳多少元素。那是容器在那块内存中总共可以容纳多少元素,而不是还可以容纳多少元素。如果想知道一个vector或string中有多少没有被占用的内存,则必须从capacity()中减去size()。如果size和capacity返回同样的值,容器中就没有剩余空间了,而下一次插入(通过insert或push_back等)会引发上面的重新分配步骤。
(3)resize(Container::size_type n)用来强制把容器改为容纳n个元素。调用resize函数之后,size函数将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会进行重新分配。
(4)reserve(Container::size_type n)强制容器把它的容量改为不小于n,提供的n不小于当前所需的大小。因为容量需要增加,这一般会强迫进行一次重新分配。如果n小于当前容量,vector会忽略它,则这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。


综上所述,只要有元素需要插入而且容器的容量不足时就会发生重新分配(包括它们维护的原始内存分配和回收,对象的拷贝和析构和迭代器、指针和引用的失效)。所以,避免重新分配的关键是使用reserve尽快把容器的容量设置为足够大,最好在容器被构造之后立刻进行。

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)步长WALK_LENGTH

定义一个步长WALK_LENGTH,在数组空间不够时,再重新申请长度为theCapacity+WALK_LENGTH的内存,这样就避免了每次当myVector元素增加的时候,需要去重新申请空间的问题,当然不好的地方就是会浪费一定的空间,但是时间效率上会提高很多

(2)构造函数

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个成本变量进行赋值,元素个数、容量大小和数组内容。

(3)清空myVector中的元素, clear()函数

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

void clear(){
    deallocator(array);
    array = 0;
    theSize = 0;
    theCapacity = 0;
}

(4)析构函数

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

~myVector(){
    clear();
}

(5)用下标的方式访问myVector中的元素,[ ]重载

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

T& operator[](unsigned int pos){
    assert(pos<theSize);
    return array[pos];
}

(6)获得元素个数和容器大小

直接返回成员变量即可,如下所示:

/*element theSize*/
unsigned int size(){
    return theSize;
}
/*alloc theSize*/
unsigned int capacity(){
    return theCapacity;
}

(7)判断myVector是否为空

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

bool empty(){
     return theSize == 0;
}

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

(9)删除某个元素

要把这个元素后面的都往前挪,并把元素个数-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)当内存不够时,需要重新申请内存,再把以前的元素复制过来,效率也比较低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值