当前位置:首页 » 《随便一记》 » 正文

【C++】手动实现C++ vector容器:深入理解动态数组的工作原理

25 人参与  2024年11月18日 11:21  分类 : 《随便一记》  评论

点击全文阅读


?个人主页: 起名字真南
?个人专栏:【数据结构初阶】 【C语言】 【C++】 【OJ题解】

请添加图片描述

目录

1. 引言2. 实现思路3. `vector` 容器的代码实现4. 代码详解4.1 构造与析构函数4.2 容量管理4.3 迭代器与访问操作4.4 增删操作 5.测试代码6. 时间和空间复杂度分析7. 总结

1. 引言

vector 是 C++ 标准模板库(STL)中最常用的动态数组容器。它不仅提供了自动扩容、快速访问、灵活增删等功能,还能高效地管理内存。本篇文章将带大家实现一个简化版的 vector,包含动态扩容、元素插入删除、访问等操作,以此深入理解其内部实现原理,尤其是动态数组的管理机制。

2. 实现思路

我们将实现的 vector 具有如下核心功能:

构造与析构:支持多种方式的构造,并在对象销毁时正确释放内存。容量管理:包括扩容、调整大小等操作。元素增删:支持尾部增删以及在任意位置插入删除元素。迭代器与访问操作:提供迭代器和下标访问方式。

3. vector 容器的代码实现

以下是完整的代码实现,功能完备,包含了构造、析构、拷贝、赋值重载、容量管理、增删操作和元素访问等基本操作:

#pragma once#include <iostream>#include <assert.h>namespace wzr {    template<class T>    class vector     {    public:        typedef T* iterator;        typedef const T* const_iterator;        // 默认构造函数        vector()         : _start(nullptr)        , _finish(nullptr),         _endOfStorage(nullptr)         {}        // 构造函数:构造n个value        vector(size_t n, const T& value = T())            : _start(nullptr)            , _finish(nullptr)            , _endOfStorage(nullptr)             {            reserve(n);            while (n--)             {                push_back(value);            }  //其实我们会发现这两串代码会有一些冗余,当我们使用vector(10,1)  //编译器在编译的时候就已经将T实例化成int类型,  //并且编译器会认为10,1是int,如果两个类型一致就会选择是区间构造,会报错。        vector(int n, const T & value = T()):_start(new T[n]), _finish(_start + n), _endOfStorage(_finish){reserve(n);for (int i = 0; i < n; i++){_start[i] = value;}}        // 拷贝构造函数        vector(const vector<T>& v)         : _start(nullptr)       , _finish(nullptr)        , _endOfStorage(nullptr)         {            reserve(v.capacity());            iterator it = begin();            const_iterator vit = v.cbegin();            while (vit != v.cend()) {                *it++ = *vit++;            }            _finish = it;        } //如果使用iterator作为迭代器进行区间初始化构造, //那么容器就是能是vector//重新声明迭代器,迭代区间[first, last)可以是任意容量的迭代器template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}        // 赋值操作符重载(采用拷贝交换优化)        vector<T>& operator=(vector<T> v)         {            swap(v);            return *this;        }        // 析构函数        ~vector() {            if (_start)             {                delete[] _start;                _start = _finish = _endOfStorage = nullptr;            }        }        // 迭代器        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;         }        bool empty() const         {         return _start == _finish;         }        // 预留空间        void reserve(size_t n)         {            if (n > capacity()) {                size_t oldSize = size();                T* tmp = new T[n];                if (_start) {                    for (size_t i = 0; i < oldSize; i++) {                        tmp[i] = _start[i];                    }                    delete[] _start;                }                _start = tmp;                _finish = _start + oldSize;                _endOfStorage = _start + n;            }        }        // 改变大小        void resize(size_t n, const T& value = T())         {            if (n <= size()) {                _finish = _start + n;            } else {                if (n > capacity()) {                    reserve(n);                }                iterator it = _finish;                _finish = _start + n;                while (it != _finish) {                    *it = value;                    it++;                }            }        }        // 元素访问        T& operator[](size_t pos)         {            assert(pos < size());            return _start[pos];        }        const T& operator[](size_t pos) const         {            assert(pos < size());            return _start[pos];        }        T& front()         {          return *_start;           }        const T& front() const         {          return *_start;          }        T& back()         {          return *(_finish - 1);           }        const T& back() const         {          return *(_finish - 1);          }        // 增删操作        void push_back(const T& value)         {         insert(end(), value);         }        void pop_back()         {         erase(end() - 1);         }        // 交换两个vector        void swap(vector<T>& v)         {            std::swap(_start, v._start);            std::swap(_finish, v._finish);            std::swap(_endOfStorage, v._endOfStorage);        }        // 插入        iterator insert(iterator pos, const T& x)         {            assert(pos <= _finish);            if (_finish == _endOfStorage) {                size_t newcapacity = (capacity() == 0 ? 1 : 2 * capacity());                reserve(newcapacity);                pos = _start + size();            }            iterator end = _finish - 1;            while (end >= pos) {                *(end + 1) = *end;                --end;            }            *pos = x;            ++_finish;            return pos;        }        // 删除        iterator erase(iterator pos)         {            iterator begin = pos + 1;            while (begin != end())             {                *(begin - 1) = *begin;                begin++;            }            --_finish;            return pos;        }    private:        iterator _start;          // 数据起始指针        iterator _finish;         // 有效数据的结束指针        iterator _endOfStorage;   // 总容量的结束指针    };}

4. 代码详解

4.1 构造与析构函数

vector():默认构造函数,初始化指针为 nullptr,用于构造空的 vectorvector(size_t n, const T& value = T()):构造一个大小为 nvector,并用 value 初始化每个元素。调用 reserve(n) 分配空间,再通过 push_back 插入元素。vector(const vector<T>& v):拷贝构造函数。分配与 v 相同的空间后,逐个拷贝 v 中的元素。vector(InputIterator first,InputIterator last):使用迭代器区间去构造函数。~vector():析构函数。释放动态分配的内存,并将所有指针置为 nullptr

4.2 容量管理

reserve(size_t n):扩容函数。若 n 大于当前容量,则分配一个大小为 n 的新空间,将原数据拷贝至新空间,并释放旧空间。resize(size_t n, const T& value = T()):调整 vector 大小。若 n 小于当前大小,则只需调整 _finish。若 n 大于容量,则扩容并初始化新增元素。

4.3 迭代器与访问操作

begin()end():返回 _start_finish,用于迭代 vectoroperator[]:通过下标访问元素,并通过 assert 检查越界访问。front()back():返回首尾元素的引用,支持首尾元素的快速访问。

4.4 增删操作

push_back(const T& value):在尾部插入元素 value。若容量不足,调用 reserve 扩容。pop_back():删除最后一个元素,通过调整 _finish 指针实现。insert(iterator pos, const T& x):在指定位置插入元素 x。若容量不足,则扩容;随后将 [pos, end) 的数据右移,腾出插入位置。erase(iterator pos):删除指定位置的元素。将 [pos + 1, end) 的数据左移一位以覆盖删除位置,更新 _finish 指针。

5.测试代码

#include"Vector.h"namespace wzr{void Test01(){vector<int> v1;vector<int> v2(10, 6);int array[] = { 1,2,3,4,5 };vector<int> v3(array, array + sizeof(array) / sizeof(array[0]));vector<int> v4(v3);for (size_t i = 0; i < v2.size(); i++){cout << v2[i] << " ";}cout << endl;auto it = v3.begin();while (it != v3.end()){cout << *it << " ";it++;}cout << endl;for (auto itt : v4){cout << itt << " ";}cout << endl;}void Test02(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);cout << v.size() << endl;cout << v.capacity() << endl;cout << v.front() << endl;cout << v.back() << endl;cout << v[0] << endl;for (auto e : v){cout << e << " ";}cout << endl;v.pop_back();v.pop_back();v.insert(v.begin(), 0);for (auto e : v){cout << e << " ";}cout << endl;v.erase(v.begin() + 1);for (auto e : v){cout << e << " ";}cout << endl;}}int main(){//wzr::Test01();wzr::Test02();return 0;}

6. 时间和空间复杂度分析

push_back:均摊时间复杂度为O(1),因为扩容后插入操作是常数时间的。pop_back:O(1)。resize:O(n)。inserterase:最坏情况时间复杂度为O(n),因为需要移动大量数据。

7. 总结

通过对各个函数的详细解析,我们手动实现了一个简化版的 vector,展示了 C++ 标准库中 vector 的核心功能。希望通过这篇文章,大家能更好地理解 vector 容器


点击全文阅读


本文链接:http://zhangshiyu.com/post/188068.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1