• 【STL***vector容器三】


    本节分析vector是如何进行插入操作的,以及数组大小不足后,insert怎么来处理

    insert()为了接受不同参数,定义了多个重载函数~~~

     insert(iterator position, const T& x) 传入一个迭代器和插入的值

    1. 如果数组还有备用空间, 并且插入的是finish位置, 直接插入即可, 最后调整finish就行了.
    2. 以上条件不成立, 调用insert_aux函数执行插入操作
    1. iterator insert(iterator position) { return insert(position, T()); }
    2. iterator insert(iterator position, const T& x) ;
    3. iterator insert(iterator position, const T& x)
    4. {
    5. size_type n = position - begin();
    6. // 如果数组还有备用空间, 并且插入的是finish位置, 直接插入即可, 最后调整finish就行了.
    7. if (finish != end_of_storage && position == end())
    8. {
    9. construct(finish, x);
    10. ++finish;
    11. }
    12. // 以上条件不成立, 调用另一个函数执行插入操作
    13. else
    14. insert_aux(position, x);
    15. return begin() + n;
    16. }

    insert_aux:

    1. void insert_aux(iterator position, const T& x);
    2. template <class T, class Alloc>
    3. void vector::insert_aux(iterator position, const T& x)
    4. {
    5. // 如果数组还有备用空间, 就直接移动元素, 再将元素插入过去, 最后调整finish就行了.
    6. if (finish != end_of_storage)
    7. {
    8. // 调用构造, 并将最后一个元素复制过去, 调整finish
    9. construct(finish, *(finish - 1));
    10. ++finish;
    11. T x_copy = x;
    12. // 将插入元素位置的后面所有元素往后移动, 最后元素插入到位置上.
    13. copy_backward(position, finish - 2, finish - 1);
    14. *position = x_copy;
    15. }
    16. // 没有备用空间, 重新申请空间再将元素拷贝过去同时执行插入操作
    17. else {
    18. const size_type old_size = size();
    19. const size_type len = old_size != 0 ? 2 * old_size : 1; // 重新申请空间原始空间的两倍+1的空间
    20. iterator new_start = data_allocator::allocate(len);
    21. iterator new_finish = new_start;
    22. __STL_TRY {
    23. // 进行分段将原始元素拷贝新的空间中, 这样也就实现了插入操作
    24. new_finish = uninitialized_copy(start, position, new_start);
    25. construct(new_finish, x);
    26. ++new_finish;
    27. new_finish = uninitialized_copy(position, finish, new_finish);
    28. }
    29. # ifdef __STL_USE_EXCEPTIONS
    30. catch(...) {
    31. destroy(new_start, new_finish);
    32. data_allocator::deallocate(new_start, len);
    33. throw;
    34. }
    35. # endif /* __STL_USE_EXCEPTIONS */
    36. // 释放掉原来的空间, 调整新的3个迭代器的位置
    37. destroy(begin(), end());
    38. deallocate();
    39. start = new_start;
    40. finish = new_finish;
    41. end_of_storage = new_start + len;
    42. }
    43. }

    void insert (iterator pos, size_type n, const T& x) 传入一个迭代器, 插入的个数, 和插入的值

    1. void insert (iterator pos, size_type n, const T& x);
    2. void insert (iterator pos, int n, const T& x)
    3. {
    4. insert(pos, (size_type) n, x);
    5. }
    6. void insert (iterator pos, long n, const T& x)
    7. {
    8. insert(pos, (size_type) n, x);
    9. }

    如果备用空间足够大, 先保存插入位置到end的距离

    1.从插入的位置到end的距离大于要插入的个数n

    • 先构造出finish-n个大小的空间, 再移动finish - n个元素的数据
    • 将插入位置后的n个元素移动
    • 元素从插入位置开始进行填充

    2.从插入的位置到end的距离小于要插入的个数

    • 先构造出n - elems_after个大小的空间, 再从finish位置初始化n - elems_after为x
    • 从插入位置开始到原来的finish位置结束全部复制到新的结束位置后面
    • 从插入位置进行填充x


    备用空间不足的时候执行

    1. 重新申请一个当前两倍的空间或者当前大小+插入的空间, 选择两者最大的方案.
    2. 进行分段复制到新的数组中, 从而实现插入
    3. 将当前数组的元素进行析构, 最后释放空间
    4. 修改3个迭代器
      1. template <class T, class Alloc>
      2. void vector::insert(iterator position, size_type n, const T& x)
      3. {
      4. if (n != 0)
      5. {
      6. // ******** 1 ***********
      7. // 备用空间足够大
      8. if (size_type(end_of_storage - finish) >= n)
      9. {
      10. T x_copy = x;
      11. // 保存插入位置到end的距离
      12. const size_type elems_after = finish - position;
      13. iterator old_finish = finish;
      14. // ******* a **********
      15. // 从插入的位置到数据结束的距离大于了要插入的个数n
      16. if (elems_after > n)
      17. {
      18. // 先构造出finish-n个大小的空间, 再移动finish - n个元素的数据
      19. uninitialized_copy(finish - n, finish, finish);
      20. finish += n;
      21. // 在将从插入位置后的n个元素移动
      22. copy_backward(position, old_finish - n, old_finish);
      23. // 元素从插入位置开始进行填充即可
      24. fill(position, position + n, x_copy);
      25. }
      26. // ********* b *********
      27. // 从插入的位置到end的距离小于了要插入的个数
      28. else
      29. {
      30. // 先构造出n - elems_after个大小的空间, 再从finish位置初始化n - elems_after为x
      31. uninitialized_fill_n(finish, n - elems_after, x_copy);
      32. finish += n - elems_after;
      33. // 从插入位置开始到原来的finish位置结束全部复制到新的结束位置后面
      34. uninitialized_copy(position, old_finish, finish);
      35. finish += elems_after;
      36. // 从插入位置进行填充x
      37. fill(position, old_finish, x_copy);
      38. }
      39. }
      40. // ******* 2 ***********
      41. // 空间不足处理
      42. else
      43. {
      44. // 重新申请一个当前两倍的空间或者当前大小+插入的空间, 选择两者最大的方案.
      45. const size_type old_size = size();
      46. const size_type len = old_size + max(old_size, n);
      47. iterator new_start = data_allocator::allocate(len);
      48. iterator new_finish = new_start;
      49. __STL_TRY
      50. {
      51. // 同样进行分段复制到新的数组中, 从而实现插入
      52. new_finish = uninitialized_copy(start, position, new_start);
      53. new_finish = uninitialized_fill_n(new_finish, n, x);
      54. new_finish = uninitialized_copy(position, finish, new_finish);
      55. }
      56. # ifdef __STL_USE_EXCEPTIONS
      57. catch(...)
      58. {
      59. destroy(new_start, new_finish);
      60. data_allocator::deallocate(new_start, len);
      61. throw;
      62. }
      63. # endif /* __STL_USE_EXCEPTIONS */
      64. // 将当前数组的元素进行析构, 最后释放空间
      65. destroy(start, finish);
      66. deallocate();
      67. // 修改3个迭代器
      68. start = new_start;
      69. finish = new_finish;
      70. end_of_storage = new_start + len;
      71. }
      72. }
      73. }

      insert(iterator position, const_iterator first, const_iterator last) 传入3个迭代器

    1. template <class T, class Alloc>
    2. void vector::insert(iterator position, const_iterator first, const_iterator last) {
    3. // 插入不为空
    4. if (first != last) {
    5. size_type n = 0;
    6. // 计算插入的长度, 并保存在n中
    7. distance(first, last, n);
    8. // 如果是剩余的空间大于插入的长度.
    9. if (size_type(end_of_storage - finish) >= n) {
    10. // 保存插入点到end的距离
    11. const size_type elems_after = finish - position;
    12. iterator old_finish = finish;
    13. // 同样比较n与插入点到end的距离, 下面的过程与上面描述的基本一致.
    14. // 从插入的位置到end的距离大于要插入的个数n
    15. if (elems_after > n) {
    16. uninitialized_copy(finish - n, finish, finish);
    17. finish += n;
    18. copy_backward(position, old_finish - n, old_finish);
    19. copy(first, last, position);
    20. }
    21. else {
    22. uninitialized_copy(first + elems_after, last, finish);
    23. finish += n - elems_after;
    24. uninitialized_copy(position, old_finish, finish);
    25. finish += elems_after;
    26. copy(first, first + elems_after, position);
    27. }
    28. }
    29. else {
    30. const size_type old_size = size();
    31. const size_type len = old_size + max(old_size, n);
    32. iterator new_start = data_allocator::allocate(len);
    33. iterator new_finish = new_start;
    34. __STL_TRY {
    35. new_finish = uninitialized_copy(start, position, new_start);
    36. new_finish = uninitialized_copy(first, last, new_finish);
    37. new_finish = uninitialized_copy(position, finish, new_finish);
    38. }
    39. # ifdef __STL_USE_EXCEPTIONS
    40. catch(...) {
    41. destroy(new_start, new_finish);
    42. data_allocator::deallocate(new_start, len);
    43. throw;
    44. }
    45. # endif /* __STL_USE_EXCEPTIONS */
    46. destroy(start, finish);
    47. deallocate();
    48. start = new_start;
    49. finish = new_finish;
    50. end_of_storage = new_start + len;
    51. }
    52. }
    53. }

    总结

    vector适合用来做随机访问很快, 也支持适合频率较低的插入和删除操作, 在每次插入和删除后迭代器都会失效, 因为不能保证操作之后迭代器的位置没有改变

  • 相关阅读:
    Optimization of DQN
    【论文笔记】Enabling technologies and tools for digital twin
    初识测开/测试
    Python语言:随机生成几个数案例分析讲解
    AI的制作思维导图
    数据库系统原理与应用教程(061)—— MySQL 练习题:操作题 21-31(五)
    可视化学习:使用WebGL实现网格背景
    go数组array
    模糊神经网络应用实例,神经网络和模糊控制
    docker 配置mongoDB
  • 原文地址:https://blog.csdn.net/weixin_53459056/article/details/126910632