zoukankan      html  css  js  c++  java
  • 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;
    }

    运行结果:

  • 相关阅读:
    install jqdatasdk
    分布式唯一ID自增(雪花算法)
    JVM内存布局及GC知识
    double涉及大数据的时候会变成科学计数法
    IDEA中的JUNIT测试
    spring boot 整合 swagger2
    springboot 报错nested exception is java.lang.IllegalStateException: Failed to check the status of the service xxxService No provider available for the service
    解决jar包依赖冲突(idea)
    IDEA中springboot的热部署
    Exception in thread "main" java.lang.AbstractMethodError: org.springframework.boot.context.config.ConfigFileApplicationListener.supportsSourceType(Ljava/lang/Class;)Z
  • 原文地址:https://www.cnblogs.com/liuamin/p/6524488.html
Copyright © 2011-2022 走看看