Vector模板類的建立與實現(一)


最近學習了數據結構,對線性表有了比較深刻的認識,並和c++中容器的實現對照了下,有了點小收獲,記錄下來。。

1,首先線性表有2種存儲結構:順序存儲結構,鏈式存儲結構。(先說順序存儲,之后看鏈表list的時候再說)順序存儲就相當於數組,連續的存儲地址,插入和刪除要移動大量的數據元素,因為地址是連續的,但是隨機訪問能力好,也就是下標訪問元素的能力。

2.對c++中vector類模板的實現,改變了數組固定大小的缺點,可以動態添加或刪除元素改變容器的大小,有很多的函數成員,使用起來也很方便。

其實vector就是可變大小的數組,支持快速隨機訪問,除了尾部之外的地方插入和刪除元素很慢。(因為要保持連續的線性存儲空間)

3.自己寫了一個vector類模板,只是實現了部分功能,一般的大小,插入,刪除,訪問等。。看了primer之后利用allocator類實現了另一個版本。

4.代碼如下Vector.h為頭文件。

/*vector是可變大小的數組,是順序存儲結構,支持快速的隨機訪問,在尾部之外的位置插入和刪除元素很慢*/
#ifndef VECTOR_H
#define VECTOR_H
#include<cassert>
#include<iostream>
using namespace std;
template<typename T>
class Vector
{
public:
   enum{ SPARE_CAPACITY = 5 };
   typedef T* iterator;
   typedef const T* const_iterator;
    
   //構造函數
   explicit Vector(int initsize = 0); //explicit是為了防止讓一個實參的構造函數發生隱式轉換
   Vector(int initsize, T value);
   Vector(iterator b, iterator e);   //接受兩個迭代器創建拷貝的構造函數 ,這里的迭代器的創建是指針,見上面
   Vector(std::initializer_list<T> l);

   Vector(const Vector &rhs);
   Vector<T>& operator=(const Vector & rhs);
   ~Vector() { delete[] elem;}


   //常量成員函數,不改變類的成員,this指針為指向常量的常量指針,因為常量對象不能調用非常量數據成員,而非常量對象都可以調用
    bool empty()const  { return thesize == 0;}
    int size() const   {return thesize;}
    int capacity() const { return thecapacity; }
    iterator begin()  {return &elem[0];}
    iterator end()  {return &elem[thesize];}   
    const_iterator cbegin()const {return &elem[0];}   
    const_iterator cend() const {return &elem[thesize];}
    
    bool operator==(const Vector<T>& rhs);                                                              
    bool operator!=(const Vector<T>& rhs);

    
    void reserve(int newcapacity);
    void resize(int newsize, const T &thevalue);
    void resize(int newsize);
    void shrink_to_fit();

    T &operator[](int index);                                   
    const T &operator[](int index) const;
    T &front();
    const T &front() const;
    T &back();
    const T &back() const;
    void push_back(const T &x);
    iterator insert(iterator b, const T &value);
    void pop_back() {thesize--;}
    iterator erase(iterator b);
    void clear();

private:
    T *elem;
    int thesize;
    int thecapacity;
};

/******************************************構造函數******************************************/
template <typename T>
Vector<T>::Vector(int initsize = 0) :thesize(initsize), thecapacity(initsize + SPARE_CAPACITY)
{
    elem = new T[thecapacity];
    assert(elem != NULL);    //存儲分配失敗則退出;
}
template<typename T>
Vector<T>::Vector(std::initializer_list<T> l)     //列表初始化,新標准
{
    thesize = l.size();
    thecapacity = thesize + SPARE_CAPACITY;
    elem = new T[thecapacity];
    assert(elem != NULL);
    int i = 0;
    auto beg = l.begin();
    while (beg != l.end() && i != thesize)
    {
        elem[i] = *beg;
        ++i;
        ++beg;
    }
}
template <typename T>
Vector<T>::Vector(int initsize, T value) :thesize(initsize), thecapacity(initsize + SPARE_CAPACITY)
{
    elem = new T[thecapacity];
    assert(elem != NULL);    //存儲分配失敗則退出;
    for (int i = 0; i != thesize; ++i)
        elem[i] = value;
}
template <typename T>
Vector<T>::Vector(iterator b, iterator e)
{
    thesize = e - b;
    thecapacity = thesize + SPARE_CAPACITY;
    elem = new T[thecapacity];
    assert(elem != NULL);
    for (int i = 0; b != e&&i != thesize; ++i)
    {
        elem[i] = *b;
        ++b;
    }
}

//拷貝構造函數,接受一個容器為另一個容器的拷貝(深拷貝)
template <typename T>
Vector<T>::Vector(const Vector &rhs)
{
    thesize = rhs.thesize;
    thecapacity = rhs.thecapacity;
    elem = new T[thecapacity];
    assert(elem != NULL);
    for (int i = 0; i != thesize; ++i)
        elem[i] = rhs.elem[i];
}

//賦值運算符
template<typename T>
Vector<T>& Vector<T>::operator=(const Vector &rhs)
{
    if (this != &rhs) //防止自賦值
    {
        delete[]elem;
        thesize = rhs.thesize;
        thecapacity = rhs.thecapacity;
        elem = new T[thecapacity];
        assert(elem != NULL);
        for (int i = 0; i != thesize; ++i)
            elem[i] = rhs.elem[i];
    }
    return *this;
}

//swap函數的實現,通常比從一個向另一個容器拷貝元素快,只是交換了兩個容器內部的數據結構,元素本身沒有交換。。
//交換的是相同類型的容器。

//assign,賦值函數的實現

/********************************************關系運算符**********************************/
//關系運算符的實現==,!=,> ,>=, <, <=
template<typename T>
bool Vector<T>::operator==(const Vector<T>& rhs)
{
    if (this->thesize == rhs.thesize)     //與容量沒有關系
    {
        int cnt = 0;
        for (int i = 0; i != thesize; i++)
            if (this->elem[i] == rhs.elem[i])
                ++cnt;
        if (cnt == thesize)
            return true;
    }
    return false;
}
template<typename T>
bool Vector<T>::operator!=(const Vector<T>& rhs)
{
    return !(*this == rhs);
}

//分配至少容納newcapacity個的元素空間
template<typename T>
void Vector<T>::reserve(int newcapacity)
{
    if (newcapacity <= thecapacity)
    {
        if (newcapacity < thecapacity / 2)   //當新的容量很小時
        {
            T *newarray = new T[newcapacity];
            int newsize = newcapacity > thesize ? thesize : newcapacity;
            for (int i = 0; i != newsize; ++i)
                newarray[i] = elem[i];
            delete[] elem;
            elem = newarray;
            thecapacity = newcapacity;
        }
        return;
    }
    T *newarray = new T[newcapacity];
    for (int i = 0; i != thesize; ++i)
        newarray[i] = elem[i];
    delete[] elem;
    elem = newarray;
    thecapacity = newcapacity;
}

//調整它的大小,若newsize<thesize,多的元素被丟棄,若相反,添加新元素,新添進來的元素初始化為thevalue
template<typename T>
void Vector<T>::resize(int newsize, const T & thevalue)
{
    if (newsize > thesize)
    {
        if (newsize > thecapacity)
            reserve(newsize * 2 + 1);
        for (int i = thesize; i != newsize; ++i) //新添進來的元素初始化為thevalue
            elem[i] = thevalue;
    }
    else if (newsize< thesize)
    {
        if (newsize<thecapacity / 2)
            reserve(newsize);
    }
    thesize = newsize;
}
template<typename T>
void Vector<T>::resize(int newsize)    //調整它的大小,若newsize<thesize,多的元素被丟棄,若相反,添加新元素,進行值初始化
{
    resize(newsize, T());
}
template<typename T>
void Vector<T>::shrink_to_fit()        //將capacity()減少為與size()相同大小
{
    reserve(thesize + SPARE_CAPACITY);
}
/**************************************訪問操作***************************************/
template<typename T>
T & Vector<T>::operator[](int index)
{
    if (index < 0 || index >= thesize)
    {
        cout << "下標超出范圍" << endl;
        return;
    }
    return elem[index];
}
template<typename T>
const T &Vector<T>::operator[](int index) const    //返回下標不能修改
{
    if (index < 0 || index >= thesize)
    {
        cout << "下標超出范圍" << endl;
        return;
    }
    return elem[index];
}
template<typename T>
T& Vector<T>::front()
{
    if (!this->empty())
        return elem[0];
}
template<typename T>
const T& Vector<T>::front() const
{
    if (!this->empty())
        return elem[0];
}
template<typename T>
T& Vector<T>::back()
{
    if (!this->empty())
        return elem[thesize - 1];
}
template<typename T>
const T& Vector<T>::back() const
{
    if (!this->empty())
        return elem[thesize - 1];
}
/******************************************插入操作*************************************/
//向容器插入元素,vector不支持push_front,但insert可以實現插入vector的任何位置,但是注意在vector除尾部之外的任何位置很慢,很耗時。。
template<typename T>
void Vector<T>::push_back(const T &x)
{
    if (thesize == thecapacity)
        reserve(2 * thecapacity);
    elem[thesize++] = x;
}
template<typename T>
T* Vector<T>::insert(iterator b, const T &value)    //返回類型為Vector<T>::iterator則出錯??
{
    if (b < this->begin() || b> this->end())  //b可以為尾后迭代器
    {
        cout << "超出范圍" << endl;
        exit(0);
    }
    int num = b - elem;
    if (thesize == thecapacity)
    {
        reserve(thesize * 2);
        b = elem + num;                         //重新分配內存后原來的指針b失效了,所以此處令b指向新分配的數組中
    }
    for (iterator p = this->end(); p > b; p--)
        *p = *(p - 1);
    *b = value;
    thesize++;
    return b;
}
//刪除操作
template<typename T>
T* Vector<T>::erase(iterator b)
{
    if (b < this->begin() || b >= this->end())  //確保迭代器在范圍內,否則未定義,b不能為尾后迭代器
    {
        cout << "超出范圍" << endl;
        exit(0);
    }
    iterator q = b + 1;
    int num = q - elem; 
    iterator p = this->end() - 1;
    for (; b < p; b++)
        *b = *(b + 1);
    thesize--;
    if (thesize <= thecapacity / 4)     //防止刪除后空閑空間太大,浪費空間
    {
        reserve(thesize + SPARE_CAPACITY);
        iterator q1 = elem + num;          //重新進行內存分配后原來的指針q可能失效了
        return q1;
    }    
    return q;
}
template<typename T>
void Vector<T>::clear()
{
    thesize = 0;
}
#endif

附上測試代碼:

#include <string>
#include<iostream>
#include"Vector.h"     //注意當這里不是標准庫的頭文件,是自己寫的,要用雙引號,整了好久,還以為程序出錯了。。
using namespace std;
int main()
{
    Vector<int> v1; 
    Vector<int> v2(5, 9);
    Vector<int> v3(v2);
    Vector<int> v4(v2.begin(), v2.end());
    if (v1.empty())
    cout <<"v1為空,大小為:"<< v1.size() << endl;
    cout << "向v1插入元素:";
    int a;
    while (cin >> a)
        v1.push_back(a);
    if (!v1.empty())
        cout << "v1不為空,大小為:" << v1.size() << "容量為:" << v1.capacity() << endl;
    cout << "元素為:";
    for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    cout << "重新插入后:";
    v1.insert(v1.begin() + 1, 4);
    cout << "此時v1大小為:" << v1.size() << "容量為:" << v1.capacity() << endl;
    cout << "元素為:";
    for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    cout << "刪除元素后為:";
    v1.pop_back();
    for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    cout << "再次刪除元素后為:";
    v1.erase(v1.begin() + 2);
    for (Vector<int>::iterator iter = v1.begin(); iter != v1.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    cout << "v2元素為:";
    for (Vector<int>::iterator iter = v2.begin(); iter != v2.end(); ++iter)
            cout << *iter << "   ";
        cout << endl;
    cout << "v3元素為:";
    for (Vector<int>::iterator iter = v3.begin(); iter != v3.end(); ++iter)
            cout << *iter << "   ";
        cout << endl;
    cout << "v4元素為:";
    for (Vector<int>::iterator iter = v4.begin(); iter != v4.end(); ++iter)
            cout << *iter << "   ";
        cout << endl;
    if (v1 == v3)
        cout << "v1與v3相等";
    else
        cout << "v1與v3不相等" << endl;
    Vector<int> v = { 1, 2, 3, 4, 5 };
    Vector<int> v5;
    v5 = v;
    cout << "v5元素為:";
    for (Vector<int>::iterator iter = v5.begin(); iter != v5.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    v5.push_back(99);

    v5.resize(2, 2);
    cout << "操作后v5元素為:";
    for (Vector<int>::iterator iter = v5.begin(); iter != v5.end(); ++iter)
        cout << *iter << "   ";
    cout << endl;
    std::cout << v5.capacity() << "\n";
    return 0;
}

運行結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM