搜索
您的当前位置:首页正文

vector模拟实现(C++)

来源:哗拓教育

vector是C++库里自带的可变大小数组的序列容器,它的使用非常强大,像一把青龙偃月刀,不过在用它玩出花样之前,还是得先练成关羽一般的本事才行。

这篇文章会讲解vector的模拟实现,学习模拟实现是为了更加灵活地使用它,而且也是在准备面试过程中必不可少的一步。

前置注意事项:

(1)需要自己开一块命名空间,与STL库的vector进行区分,同时也是方便调试,如果不知道命名空间的小伙伴可看这篇文章

(2)需要了解模板相关的知识,简单理解就是类似typedef了一个类,可以取代任何数据类型

1. vector成员变量

与之前的顺序表()类似,有size和capacity,不过C++有独特的表示方式,就是迭代器。 

vector通过指向开头和结尾的迭代器来间接表示size,同时定义一个容量的结尾来表示capacity,同时提供对应的接口供用户使用,同时部分使用const返回值,避免被修改

namespace myvector
{

    template<class T>
    class vector
    {    
    public:
        typedef T* iterator;
        typedef const T* const_iterator;

        // 提供接口来访问
        iterator begin()
        {
            return _start;
        }

        iterator end()
        {
            return _finish;
        }

        const_iterator cbegin() const
        {
            return _start;
        }

        const_iterator cend() const
        {
            return _finish;
        }

        size_t size() const
        {
            return _finish - _start;
        }

        size_t capacity() const
        {
            return _endOfStorage - _start;
        }

    private:
        iterator _start;        // 指向数据块的开始
        iterator _finish;       // 指向有效数据的尾
        iterator _endOfStorage; // 指向存储容量的尾
    };
}

2. reserve和resize

这两个函数很容易混,前者是开空间,后者是开空间加赋值,还可以删除元素

先写这两个函数是因为后面很多的函数都会复用他们

void reserve(size_t n)
{
    if (n > capacity())
    {
        T* tmp = new T[n];
        size_t oldSize = size();
        for (int i = 0; i < oldSize; i++)
        {
            tmp[i] = _start[i];
        }
        delete[] _start;
        _start = tmp;
        _finish = tmp + oldSize;
        _endOfStorage = tmp + n;
    }
}


void resize(size_t n, const T& value = T())
{
    if (n > size())
    {
        reserve(n);
        while(_finish < _start + n)
        {
            *_finish = value;
            ++_finish;
        }
           
    }
    else
        _finish = _start + n;

}

【注意事项】

【以下为错误代码】

void reserse(int n)
{
	if (n > (int)capacity())
	{
				
		size_t oldSize = size();
		T* tmp = new T[n];
		if (_start)//防止指针为空
		{
			//浅拷贝
			memcpy(tmp,_start,sizof(T)*n)
			delete[]_start;
		}
		_start = tmp;
		_finish =_start + oldSize;
		_endOfStorage = _start + n;
	}
}

3. insert和erase

void insert(iterator pos, const T& x)
{
    assert(pos >= _start);
    assert(pos <= _finish);

    if (_finish == _endOfStorage)
    {
        // reserve可能会改变_start的值,所以先记录一下插入的位置len
        size_t len = pos - _start;
        reserve(capacity() == 0 ? 4 : capacity() * 2);
        pos = _start + len;
    }

    iterator it = _finish - 1;
    // 依次插入
    while (it >= pos)
    {
        *(it + 1) = *it;
        it--;
    }
    *pos = x;
    ++_finish;
}

iterator erase(iterator pos)
{
    assert(pos >= _start);
    assert(pos < _finish);

    iterator it = pos + 1;
    while (it < _finish)
    {
        *(it - 1) = *it;
        ++it;
    }
    --_finish;
    return pos;
}

4. push_back和pop_back

void push_back(const T& x)
{
	if (_finish == _endofstorage) 
		reserve(capacity() == 0 ? 4 : 2 * capacity()); 
	
	*_finish = x; 
	_finish++; 
}

void pop_back()
{
	assert(size()); 
	_finish--; 
}

【版本二】复用insert和erase

void push_back(const T& x)
{
   insert(end(), x);
}

void pop_back()
{
    erase(end() - 1);
}

5. 构造和析构

包括无参构造函数、拷贝构造、迭代器构造等等

无参构造函数使用初始化列表初始化

vector()
    :_start(nullptr)
    , _finish(nullptr)
    , _endofstorage(nullptr)
{}


vector(int n, const T& value = T())
{
    // 这里的缺省值不能给0,因为传的参数可能为自定义类型或容器
    reserve(n);
    for (size_t i = 0; i < n; i++)
        push_back(value); 
}

vector(size_t n, const T& value = T())
{
    // 这里的缺省值不能给0,因为传的参数可能为自定义类型或容器
    reserve(n);
    for (size_t i = 0; i < n; i++)
        push_back(value); 
}

template<class InputIterator>
vector(InputIterator first, InputIterator last)
{
    while (first != last)
    {
        push_back(*first);
        ++first;
    }
}

vector(const vector<T>& v)
{
    reserve(v.capacity());
    for (auto& e : v)
        push_back(e);
}

// 析构
~vector()
{
    delete[] _start;
    _start = _finish = _endOfStorage = nullptr;
}

【注意点】

(1)这里的迭代器构造并不是直接使用 vector 的 iterator,而是使用模板迭代器,也就是说这里可以传其他容器的迭代器

(2)构造2函数的缺省值给的是默认无参构造,这个属于匿名对象,val是它的引用,所以相当于延长了它的生命周期;而匿名对象是临时变量,临时变量具有常性,所以需要用const修饰

(3)拷贝构造的范围for最好使用引用,避免当元素是容器和自定义变量时调用拷贝构造

(4)这里定义了 vector(size_t n, const T& value = T()) 和 vector(int n, const T& value = T())两个重载的函数,为了避免传两个整型时调用到迭代器构造去了

【拷贝构造的写法二】

这里就相当于把reserve和push_back结合起来了

vector(const vector<T>& v)
	:_start(nullptr)
	, _finish(nullptr)
	, _endofstorage(nullptr)
{
	_start = new T[v.capacity()]; 
	for (size_t i = 0; i < v.size(); i++) 
	{
		_start[i] = v[i];
	}
	_finish = _start + v.size(); 
	_endofstorage = _start + v.capacity(); 
}

6. 重载

T& operator[](size_t pos)
{
    assert(pos < size());
    return _start[pos];
}

const T& operator[](size_t pos)const
{
    assert(pos < size());
    return _start[pos];
}

vector<T>& operator=(const vector<T>& v)
{
	if (this != &v) // 避免给自己赋值
	{
		delete[] _start; 
		_start = new T[v.capacity()]; 
		for (size_t i = 0; i < v.size(); i++) 
		{
			_start[i] = v[i];
		}
		_finish = _start + v.size(); 
		_endofstorage = _start + v.capacity();
	}
	return *this; // 支持连续赋值
}

【运算符重载版本二】

void swap(vector<T>& v)
{
    std::swap(_start, v._start);
    std::swap(_finish, v._finish);
    std::swap(_endOfStorage, v._endOfStorage);
}

vector<T>& operator= (vector<T> v)
{
    swap(v);
    return *this;
}

注意:这里的std::不能省略,否则就会就近调用这个swap函数

[代码汇总]

template<class T>
class vector
{
public:
    typedef T* iterator;
    typedef const T* const_iterator;

    iterator begin()
    {
        return _start;
    }

    iterator end()
    {
        return _finish;
    }

    const_iterator cbegin() const
    {
        return _start;
    }

    const_iterator cend() const
    {
        return _finish;
    }


        
    // construct and destroy

    vector()
        :_start(nullptr)
        , _finish(nullptr)
        , _endofstorage(nullptr)
    {}


    vector(int n, const T& value = T())
    {
        reserve(n);
        for (size_t i = 0; i < n; i++)
            push_back(value); 
    }

    template<class InputIterator>
    vector(InputIterator first, InputIterator last)
    {
        while (first != last)
        {
            push_back(*first);
            ++first;
        }
    }

    vector(const vector<T>& v)
    {
        reserve(v.capacity());
        for (auto& e : v)
            push_back(e);
    }

    vector<T>& operator= (vector<T> v)
    {
        swap(v);
        return *this;
    }

    ~vector()
    {
        delete[] _start;
        _start = _finish = _endOfStorage = nullptr;
    }

    // capacity

    size_t size() const
    {
        return _finish - _start;
    }

    size_t capacity() const
    {
        return _endOfStorage - _start;
    }

    void reserve(size_t n)
    {
        if (n > capacity())
        {
            T* tmp = new T[n];
            size_t oldSize = size();
            for (int i = 0; i < oldSize; i++)
            {
                tmp[i] = _start[i];
            }
            delete[] _start;
            _start = tmp;
            _finish = tmp + oldSize;
            _endOfStorage = tmp + n;
        }
    }


    void resize(size_t n, const T& value = T())
    {
        if (n > size())
        {
            reserve(n);
            while(_finish < _start + n)
            {
                *_finish = value;
                ++_finish;
            }
           
        }
        else
            _finish = _start + n;

    }

    ///access///

    T& operator[](size_t pos)
    {
        assert(pos < size());
        return _start[pos];
    }

    const T& operator[](size_t pos)const
    {
        assert(pos < size());
        return _start[pos];
    }



    ///modify/

    void push_back(const T& x)
    {
        insert(end(), x);
    }

    void pop_back()
    {
        erase(end() - 1);
    }

    void swap(vector<T>& v)
    {
        std::swap(_start, v._start);
        std::swap(_finish, v._finish);
        std::swap(_endOfStorage, v._endOfStorage);
    }

    void insert(iterator pos, const T& x)
    {
        assert(pos >= _start);
        assert(pos <= _finish);

        if (_finish == _endOfStorage)
        {
            size_t len = pos - _start;
            reserve(capacity() == 0 ? 4 : capacity() * 2);
            pos = _start + len;
        }

        iterator it = _finish - 1;
        while (it >= pos)
        {
            *(it + 1) = *it;
            it--;
        }
        *pos = x;
        ++_finish;
    }

    iterator erase(iterator pos)
    {
        assert(pos >= _start);
        assert(pos < _finish);

        iterator it = pos + 1;
        while (it < _finish)
        {
            *(it - 1) = *it;
            ++it;
        }
        --_finish;
        return pos;
    }

private:
        
    iterator _start;// 指向数据块的开始

    iterator _finish; // 指向有效数据的尾

    iterator _endOfStorage; // 指向存储容量的尾

};

如果感到有收获的话,不妨点个赞,感谢大家的支持!

因篇幅问题不能全部显示,请点此查看更多更全内容

Top