【STL***vector容器三】

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

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

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

  1. 如果数组还有备用空间, 并且插入的是finish位置, 直接插入即可, 最后调整finish就行了.
  2. 以上条件不成立, 调用insert_aux函数执行插入操作
iterator insert(iterator position) { return insert(position, T()); }
iterator insert(iterator position, const T& x) ;

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

insert_aux:

void insert_aux(iterator position, const T& x);

template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) 
{
     // 如果数组还有备用空间, 就直接移动元素, 再将元素插入过去, 最后调整finish就行了.
  if (finish != end_of_storage) 
  {
      // 调用构造, 并将最后一个元素复制过去, 调整finish
    construct(finish, *(finish - 1));
    ++finish;
    T x_copy = x;
      // 将插入元素位置的后面所有元素往后移动, 最后元素插入到位置上.
    copy_backward(position, finish - 2, finish - 1);
    *position = x_copy;
  }
   // 没有备用空间, 重新申请空间再将元素拷贝过去同时执行插入操作
  else {
    const size_type old_size = size();
    const size_type len = old_size != 0 ? 2 * old_size : 1;	// 重新申请空间原始空间的两倍+1的空间

    iterator new_start = data_allocator::allocate(len);
    iterator new_finish = new_start;
    __STL_TRY {
        // 进行分段将原始元素拷贝新的空间中, 这样也就实现了插入操作
      new_finish = uninitialized_copy(start, position, new_start);
      construct(new_finish, x);
      ++new_finish;
      new_finish = uninitialized_copy(position, finish, new_finish);
    }

#       ifdef  __STL_USE_EXCEPTIONS 
    catch(...) {
      destroy(new_start, new_finish); 
      data_allocator::deallocate(new_start, len);
      throw;
    }
#       endif /* __STL_USE_EXCEPTIONS */
      // 释放掉原来的空间, 调整新的3个迭代器的位置
    destroy(begin(), end());
    deallocate();
    start = new_start;
    finish = new_finish;
    end_of_storage = new_start + len;
  }
}

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

void insert (iterator pos, size_type n, const T& x);
void insert (iterator pos, int n, const T& x) 
{
      insert(pos, (size_type) n, x);
}
void insert (iterator pos, long n, const T& x) 
{
      insert(pos, (size_type) n, x);
}        

如果备用空间足够大, 先保存插入位置到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个迭代器
    template <class T, class Alloc>
    void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) 
    {
    	if (n != 0) 
      	{
            // ******** 1 ***********
            // 备用空间足够大
        	if (size_type(end_of_storage - finish) >= n) 
        	{
          		T x_copy = x;
                // 保存插入位置到end的距离
          		const size_type elems_after = finish - position;
          		iterator old_finish = finish;
                // ******* a **********
                // 从插入的位置到数据结束的距离大于了要插入的个数n
          		if (elems_after > n) 
          		{
                    // 先构造出finish-n个大小的空间, 再移动finish - n个元素的数据
            		uninitialized_copy(finish - n, finish, finish);
            		finish += n;
                    // 在将从插入位置后的n个元素移动
            		copy_backward(position, old_finish - n, old_finish);
                    // 元素从插入位置开始进行填充即可
            		fill(position, position + n, x_copy);
          		}
                // ********* b *********
                // 从插入的位置到end的距离小于了要插入的个数
          		else 
                {
                    // 先构造出n - elems_after个大小的空间, 再从finish位置初始化n - elems_after为x
            		uninitialized_fill_n(finish, n - elems_after, x_copy);
            		finish += n - elems_after;
                    // 从插入位置开始到原来的finish位置结束全部复制到新的结束位置后面
            		uninitialized_copy(position, old_finish, finish);
            		finish += elems_after;
                    // 从插入位置进行填充x
            		fill(position, old_finish, x_copy);
          		}
        	}
            // ******* 2 ***********
            // 空间不足处理
        	else 
        	{
                // 重新申请一个当前两倍的空间或者当前大小+插入的空间, 选择两者最大的方案.
    	      	const size_type old_size = size();        
    	      	const size_type len = old_size + max(old_size, n);
    	      	iterator new_start = data_allocator::allocate(len);
    	      	iterator new_finish = new_start;
    	      	__STL_TRY 
    	        {
                    // 同样进行分段复制到新的数组中, 从而实现插入
    		        new_finish = uninitialized_copy(start, position, new_start);
    	        	new_finish = uninitialized_fill_n(new_finish, n, x);
    	        	new_finish = uninitialized_copy(position, finish, new_finish);
        	  	}
    #         ifdef  __STL_USE_EXCEPTIONS 
          		catch(...) 
          		{
    	        	destroy(new_start, new_finish);
        	    	data_allocator::deallocate(new_start, len);
            		throw;
          		}
    #         endif /* __STL_USE_EXCEPTIONS */
                // 将当前数组的元素进行析构, 最后释放空间
          		destroy(start, finish);
          		deallocate();
                // 修改3个迭代器
          		start = new_start;
          		finish = new_finish;
          		end_of_storage = new_start + len;
        	}
    	}
    }
    

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

template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, const_iterator first, const_iterator last) {
// 插入不为空
  if (first != last) {
    size_type n = 0;
    // 计算插入的长度, 并保存在n中
    distance(first, last, n);
    // 如果是剩余的空间大于插入的长度.
    if (size_type(end_of_storage - finish) >= n) {
    	// 保存插入点到end的距离
      const size_type elems_after = finish - position;
      iterator old_finish = finish;
      	// 同样比较n与插入点到end的距离, 下面的过程与上面描述的基本一致.
      	// 从插入的位置到end的距离大于要插入的个数n
      if (elems_after > n) {
        uninitialized_copy(finish - n, finish, finish);
        finish += n;
        copy_backward(position, old_finish - n, old_finish);
        copy(first, last, position);
      }
      else {
        uninitialized_copy(first + elems_after, last, finish);
        finish += n - elems_after;
        uninitialized_copy(position, old_finish, finish);
        finish += elems_after;
        copy(first, first + elems_after, position);
      }
    }
    else {
      const size_type old_size = size();
      const size_type len = old_size + max(old_size, n);
      iterator new_start = data_allocator::allocate(len);
      iterator new_finish = new_start;
      __STL_TRY {
        new_finish = uninitialized_copy(start, position, new_start);
        new_finish = uninitialized_copy(first, last, new_finish);
        new_finish = uninitialized_copy(position, finish, new_finish);
      }
#         ifdef __STL_USE_EXCEPTIONS
      catch(...) {
        destroy(new_start, new_finish);
        data_allocator::deallocate(new_start, len);
        throw;
      }
#         endif /* __STL_USE_EXCEPTIONS */
      destroy(start, finish);
      deallocate();
      start = new_start;
      finish = new_finish;
      end_of_storage = new_start + len;
    }
  }
}

总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值