STL库容器之vector、List的模拟实现

什么是STL

STL是标准模板库。

STL六大组件

容器 迭代器 算法 仿函数 适配器(adapter) 空间配置器(allocator)
vector\list \deques是一种数据结构 (如同一个指针)提供了访问容器对象的方法,而且不暴露对象的私有成员保持封装,减少了学习成本 操作容器中的数据的模板函数(find()函数就在算法中)与数据类型无关,高度复用 类比电源适配器,有了适配器就可以很好的使用数据结构(queue、stack(用vector或者list适配出来的)) 解决空间分配

STL::vector模拟实现

这里写图片描述
常用接口的实现:

Insert(在某一固定位置插入元素)

Iterator Insert(Iterator pos, T& x){
        assert(pos <=_finish);
        size_t offset = pos - _start;
        if (_finish == _endofstorage){
            Expand(2 * Capcity);
            pos = _start + offset;
        }
        Iterator end = _finish - 1;
        while (pos <= end){
            *(end + 1) = *end;
            --end;
        }
        *pos = x;
        ++_finish;
        return pos;
    }

Erase(删除指定位置的元素)

Iterator Erase(Iterator pos){
        assert(pos >= _start&&pos <= _finish);
        while (pos+1 < _finish){
            *pos = *(pos + 1);
            ++pos;
        }
        --_finish;
        return pos;
    }

上面函数之所以要设计返回值,是为了避免迭代器失效的问题

增容相关的函数(Reserve、Resize)

1、Reserve:意思是预留空间,一次性将空间开好,可以避免频繁的向内存申请空间,提高效率。
只影响空间

    void Reserve(int n){
        if (n > Capacity()){
            Expand(n);
        }
    }

2、Resize:分三个方面来讲解:其一假如传参的n大于capacity,那么就是简单的增容,其二假如n介于_finish到_endofstorage,那么就会做一件事,将原来_finish后面的到_endofstorage这一段数据置成相应的值;其三:n小于_finish,此时容量不会变但是size会减少到n.
不仅可以增容,还可以减少有效数据的范围

void Resize(size_t n,T x=T()){
        if (n <= Size()){
            _finish = _start + n;
        }
        else{
            if (n > Capacity()){
                Expand(n);
            }
            while (_finish < _start + n){
                *_finish = x;
                ++_finish;
            }
        }
    }

3、自己实现的增容函数,expand()。通常是以两倍来增的,(库中是1.5倍)
**为什么增容一次增两倍呢?(面试题)
因为假如增大于两倍但是却只插入了一次数据,那么剩下的空间就全部浪费了,相反如果只增加一倍,那么就只能满足一次复制,再有其他的操作就有得开空间了,所以效率很低,权衡之下,增两倍比较合适。

    void Expand(size_t n){
        if (n > Capacity()){
            T* tmp = new T[n];
            size_t  size = Size();
            for (size_t i = 0; i < size; i++){
                tmp[i] = _start[i];
            }
            delete[] _start;
            _start = tmp;
            _finish = _start + size;
            _endofstorage = _start + n;
        }
    }

完整代码:

#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
template<class T>
class MyVector{
public:
    typedef T* Iterator;
    typedef const T* ConstIterator;

    MyVector()
        :_start(NULL)
        , _finish(NULL)
        , _endofstorage(NULL)
    {}

    MyVector(const MyVector<T>& v){
        if (Size()< v.Size()){
            delete[]_start;
            _start = new T[v.Size()];
            _finish = _start;
        }
        for (Iterator tmp = v._start; tmp != v._finish; ++tmp){
            *_finsh = *tmp;
            _finish++;
        }
        _endofstorage = _finish;
    }
    MyVector<T>& operator=(const MyVector<T>& v){
        if (this != &v){
            swap(_start, v._start);
            swap(_finish, v._finish);
            swap(_endofstorage, v._endofstorage);
        }
        return *this;
    }
    ~MyVector(){
        if (_start){
            delete[] _start;
            _start = _finish = _endofstorage = NULL;
        }
    }
    void Expand(size_t n){
        if (n > Capacity()){
            T* tmp = new T[n];
            size_t  size = Size();
            for (size_t i = 0; i < size; i++){
                tmp[i] = _start[i];
            }
            delete[] _start;
            _start = tmp;
            _finish = _start + size;
            _endofstorage = _start + n;
        }
    }
    size_t Size(){
        return _finish - _start;
    }
    size_t Capacity(){
        return _endofstorage - _start;
    }
    void PushBack(const T& x){
        if (_finish == _endofstorage){
            size_t capacity = Capacity();
            capacity = capacity == 0 ? 3 : 2 * capacity;
            Expand(capacity);
        }
        *_finish = x;
        ++_finish;
    }
//此处会有迭代器失效的问题,因为插入数据时可能会有空间不足的问题,
//那么就需要开一块更大的空间,
//然后将数据依次拷贝到新空间,在释放就空间,所以释放了
//pos原来的位置就找不到了,所以需要记住pos相对_start的位置
    Iterator Insert(Iterator pos, T& x){
        assert(pos <=_finish);
        size_t offset = pos - _start;
        if (_finish == _endofstorage){
            Expand(2 * Capcity);
            pos = _start + offset;
        }
        Iterator end = _finish - 1;
        while (pos <= end){
            *(end + 1) = *end;
            --end;
        }
        *pos = x;
        ++_finish;
        return pos;
    }
    Iterator Erase(Iterator pos){
        assert(pos >= _start&&pos <= _finish);
        while (pos+1 < _finish){
            *pos = *(pos + 1);
            ++pos;
        }
        --_finish;
        return pos;
    }
    T& operator[](size_t pos){
        assert(pos < Size());
        return _start[pos];
    }
//将迭代器封装两份主要是在于打印vector的时候,有时候希望只读不写,
//有时候希望读的时候改它,所以根据是否是const迭代器来判断使用哪个
    Iterator Begin(){
        return _start;
    }
    Iterator End(){
        return _finish;
    }
    ConstIterator Begin() const{
        return _start;
    }
    ConstIterator End() const{
        return _finish;
    }
    void PopBack(){
        if (_start != _finish){
            --_finish;
        }
    }
    //只对空间有影响
    void Reserve(int n){
        if (n > Capacity()){
            Expand(n);
        }
    }
    //n小于size的时候会缩小size,大于capacity扩容,两者之间会在原来数据的后面追加默认值(n-size)个
void Resize(size_t n,T x=T()){
        if (n <= Size()){
            _finish = _start + n;
        }
        else{
            if (n > Capacity()){
                Expand(n);
            }
            while (_finish < _start + n){
                *_finish = x;
                ++_finish;
            }
        }
    }
private:
    //使用迭代器包裹私有成员,降低学习成本
    Iterator _start;
    Iterator _finish;
    Iterator _endofstorage;

    /*T* _start;
    T* _finish;
    T* _endofstorage;*/
};
void PrintVector(const MyVector<int>& v1){
    MyVector<int>::ConstIterator it1 = v1.Begin();
    //我们会发现此处报错,因为我们希望vector只被读,但是由于迭代器的原因,会将我们的const 传给非const
    while (it1 < v1.End()){
        cout << *it1 << " ";
        ++it1;
    }
    cout << endl;
}
void PrintVector2(MyVector<int>& v1){
    MyVector<int>::Iterator it1 = v1.Begin();
    while (it1 < v1.End()){
        *it1 += 4;
        cout << *it1 << " ";
        ++it1;
    }
    cout << endl;
}
void TestVector(){
    MyVector<int> v1;
    v1.PushBack(1);
    v1.PushBack(2);
    v1.PushBack(3);
    v1.PushBack(4);
    v1.PushBack(5);
    v1.PushBack(6);
    PrintVector(v1);
    MyVector<int>::Iterator it = v1.Begin();
    while (it != v1.End()){
        if (*it % 2 == 0){
            v1.Erase(it);
        }
        else{
            ++it;
        }
    }
    PrintVector(v1);

    /*cout << "size:" << v1.Size() << endl;
    cout << "capacity:" << v1.Capacity() << endl;
    v1.Reserve(12);
    PrintVector(v1);
    cout << "size:" << v1.Size() << endl;
    cout << "capacity:" << v1.Capacity() << endl;
    v1.Resize(12);
    PrintVector(v1);
    PrintVector2(v1);*/
}

List常用接口的实现(待完成)

猜你喜欢

转载自blog.csdn.net/cx2479750196/article/details/80715770
今日推荐