• 【C++】vector


    vector基本介绍

    1. vector 表示可变大小数组的序列容器。
    2. 就像数组一样, vector 也采用的连续存储空间来存储元素。也就是意味着可以采用下标对 vector 的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
    3. 本质讲, vector 使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector 并不会每次都重新分配大小。
    4. vector 分配空间策略: vector 会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
    5. 因此, vector 占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
    6. 与其它动态序列容器相比( deque, list and forward_list ), vector 在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list forward_list统一的迭代器和引用更好

    vector的构造

    无参构造
    explicit vector (const allocator_type& alloc = allocator_type());

    构造并初始化nval

    explicit vector (size_type n, const value_type& val = value_type(),
                     const allocator_type& alloc = allocator_type());
    

    使用迭代器进行初始化构造

    template 
             vector (InputIterator first, InputIterator last,
                     const allocator_type& alloc = allocator_type());

    拷贝构造

    vector (const vector& x);
    vector迭代器
    begin + end
    获取第一个数据位置的 iterator/const_iterator , 获取最后一个数据的下一个位置的iterator/const_iterator
    rbegin + rend
    获取最后一个数据位置的 reverse_iterator ,获取第一个数据前一个位置的reverse_iterator

    vector容量相关函数

    size   获取数据个数
    size_type size() const;(由于size一般只涉及读的操作,因此只提供了const只读的函数)
    capacity   获取容量大小
    size_type capacity() const;
    empty   判断是否为空
    bool empty() const;
    resize   改变vector 的size
    void resize (size_type n, value_type val = value_type());(如果n小于size,则修改size到n,数据截断;如果n大于size,则修改size到n,如果提供了val,则多余的部分初始化为val,如果没有提供,则默认初始化为value_type(),如果此时的n大于capacity,还会扩容)
    reserve   改变vector 的capacity
    void reserve (size_type n);(如果n大于capacity则会扩容,其他条件capacity保持不变,且不会影响size)
    capacity 的代码在 vs g++ 下分别运行会发现, vs capacity 是按 1.5 倍增长的, g++ 是按 2 倍增长的 。不要固化的认为,vector 增容都是 2 倍,具体增长多少是根据具体的需求定义 的。vs PJ 版本 STL g++ SGI 版本 STL
    reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代价缺陷问题。
    resize 在开空间的同时还会进行初始化,影响 size

    vector增删查改相关函数

    push_back  尾插
    void push_back (const value_type& val);
    pop_back  尾删
    void pop_back();
    find 查找(注意这个是算法模块实现,不是vector 的成员接口)
    insert 在position 之前插入 val
    (注意这里的insert的返回值是一个迭代器)
    erase 删除position 位置的数据或者某段区间,这里的区间是左闭右开
    swap 交换两个vector 的数据空间
    void swap (vector& x);
    operator[ ]  像数组一样访问(运算符重载)

    vector模拟实现

    结构上我们模仿库里面的实现方式,如上图成员变量是三个指针:begin、finish、end_of_storage

    vector构造&拷贝构造&析构&赋值运算符重载

    迭代器

    reserve函数

    其他函数的实现

    完整代码

    1. #include
    2. #include
    3. namespace my_vector
    4. {
    5. template<class T>
    6. class vector
    7. {
    8. public:
    9. typedef T* iterator;
    10. typedef const T* const_iterator;
    11. iterator begin()
    12. {
    13. return _start;
    14. }
    15. iterator end()
    16. {
    17. return _finish;
    18. }
    19. const_iterator begin() const
    20. {
    21. return _start;
    22. }
    23. const_iterator end() const
    24. {
    25. return _finish;
    26. }
    27. vector()
    28. :_start(nullptr)
    29. ,_finish(nullptr)
    30. ,_endofstorage(nullptr)
    31. {}
    32. vector(const vector& v)
    33. :_start(nullptr)
    34. , _finish(nullptr)
    35. , _endofstorage(nullptr)
    36. {
    37. _start = new T[v.capacity()];
    38. //memcpy(_start, v._start, sizeof(T)*v.size());
    39. for (size_t i = 0; i < v.size(); i++)
    40. {
    41. _start[i] = v._start[i];//T是string这样的深拷贝的类,调用的是string赋值重载,实现string对象的深拷贝
    42. }
    43. _finish = _start + v.size();
    44. _endofstorage = _start + v.capacity();
    45. }
    46. vector(size_t n, const T& val = T())
    47. :_start(nullptr)
    48. , _finish(nullptr)
    49. , _endofstorage(nullptr)
    50. {
    51. resize(n, val);
    52. }
    53. vector(int n, const T& val = T())
    54. :_start(nullptr)
    55. , _finish(nullptr)
    56. , _endofstorage(nullptr)
    57. {
    58. resize(n, val);
    59. }
    60. template<class InputIterator>
    61. vector(InputIterator first, InputIterator last)
    62. {
    63. while (first != last)
    64. {
    65. push_back(*first);
    66. ++first;
    67. }
    68. }
    69. void swap(vector& v)
    70. {
    71. std::swap(_start, v._start);
    72. std::swap(_finish, v._finish);
    73. std::swap(_endofstorage, v._endofstorage);
    74. }
    75. vector operator=(vector v)//传值传参,调用拷贝构造
    76. {
    77. swap(v);
    78. return *this;
    79. }
    80. ~vector()
    81. {
    82. if (_start)
    83. {
    84. delete[] _start;
    85. _start = _finish = _endofstorage = nullptr;
    86. }
    87. }
    88. void reserve(size_t n)
    89. {
    90. if (n > capacity())
    91. {
    92. size_t sz = size();
    93. T* tmp = new T[n];
    94. if (_start)
    95. {
    96. //memcpy(tmp, _start, sizeof(T) * sz);//如果vector内存的是自定义类型,虽然vector的拷贝是深拷贝,但vector数组里对自定义类型的对象,memcpy只是浅拷贝
    97. //因此delete[] _start会依次调用vector数组中每个对象的析构函数,再释放整个空间
    98. for (size_t i = 0; i < sz; i++)
    99. {
    100. tmp[i] = _start[i];//调用自定义类型的赋值操作(实现时是深拷贝)
    101. }
    102. delete[] _start;
    103. }
    104. _start = tmp;
    105. _finish = _start + sz;
    106. _endofstorage = _start + n;
    107. }
    108. }
    109. void push_back(const T& x)
    110. {
    111. if (_finish == _endofstorage)
    112. {
    113. size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
    114. reserve(newcapacity);
    115. }
    116. *_finish = x;
    117. ++_finish;
    118. }
    119. size_t capacity() const
    120. {
    121. return _endofstorage - _start;
    122. }
    123. size_t size() const
    124. {
    125. return _finish - _start;
    126. }
    127. void operator[](size_t pos)
    128. {
    129. assert(pos < size());
    130. return _start[pos];
    131. }
    132. void operator[](size_t pos) const
    133. {
    134. assert(pos < size());
    135. return _start[pos];
    136. }
    137. iterator erease(iterator pos)
    138. {
    139. assert(pos >= _start && pos <= _finish);
    140. iterator it = pos + 1;
    141. while (it != _finish)
    142. {
    143. *(it - 1) = *it;
    144. ++it;
    145. }
    146. --_finish;
    147. return pos;
    148. }
    149. iterator insert(iterator pos, const T& x)
    150. {
    151. assert(pos >= _start && pos <= _finish);
    152. if (_finish == _endofstorage)
    153. {
    154. size_t len = pos - _start;
    155. size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
    156. reserve(newcapacity);
    157. pos = _start + len;//避免内部的迭代器失效(防止pos成为野指针,通过计算相对位置,重新确定pos位置)
    158. }
    159. iterator end = _finish - 1;
    160. while (end >= pos)
    161. {
    162. *(end + 1) = *end;
    163. --end;
    164. }
    165. *pos = x;
    166. ++_finish;
    167. return pos;//返回新插入位置的指针,防止外部调用insert之后依然使用形参迭代器pos,可能导致迭代器失效
    168. }
    169. void resize(size_t n, const T& val = T())//缺省值给的是T的匿名对象
    170. {
    171. if (n < size())
    172. {
    173. _finish = _start + n;
    174. }
    175. else
    176. {
    177. reserve(n);
    178. while (_finish != _start + n)
    179. {
    180. *_finish = val;
    181. ++_finish;
    182. }
    183. }
    184. }
    185. private:
    186. iterator _start;
    187. iterator _finish;
    188. iterator _endofstorage;
    189. };
    190. }

  • 相关阅读:
    2023年【北京市安全员-B证】考试试卷及北京市安全员-B证模拟考试题
    二、网络编程
    Spring IOC 设计结构
    MongoDB备份与恢复以及导入导出
    MySQL 高可用之MHA 工作原理和架构,实现MHA高可用实战案例
    利用CNN进行手写数字识别
    .Net Core 3.0 对 MongoDB 的多条件(两种)查询操作
    前端基础建设与架构26 如何设计一个“万能”项目脚手架?
    VB.NET—DataGridView控件教程详解
    Python3高级特性(一)之切片
  • 原文地址:https://blog.csdn.net/m0_73737172/article/details/133865548