最近学习了数据结构,对线性表有了比较深刻的认识,并和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;
}

运行结果:

 

posted on 2017-03-10 17:18  liuamin  阅读(10445)  评论(0编辑  收藏  举报