C++ 向量 vector

向量数组到向量C/C++中,数组A[]中的元素[0,n)内的编号一一对应,有A[0],A[1],A[2],...,A[n-1];并且每一个元素均可由(非负)编号唯一指代,并且**可以直接访问**,A[i]的物理地址是A+i*s(s是单个元素暂用的空间量),也称作线性数组。向量由数组抽象来,由一组元素按照线性次序封装,各个元素[0,n)内的秩(int ,c++对应iterator),元素类型不...
摘要由CSDN通过智能技术生成

数组到向量

C/C++中,数组A[]中的元素[0,n)内的编号一一对应,有A[0],A[1],A[2],…,A[n-1];并且每一个元素均可由(非负)编号唯一指代,并且可以直接访问,A[i]的物理地址是A+i*s(s是单个元素暂用的空间量),也称作线性数组。
向量由数组抽象来,由一组元素按照线性次序封装,各个元素[0,n)内的秩(int ,c++对应iterator),元素类型不限于基本类型,操作、管理和维护更为简化、统一、安全,可以更为便捷的参与复杂数据结构的定制与实现。
优点在于支持内存连续,支持随机访问。但是为了保证内存连续性,插入和删除操作需要对后续所有元素全部执行一次搬移。

c++ std::vector

定义

template<class _Ty,	class _Alloc = allocator<_Ty> >
	class vector
			: public _Vector_alloc<!is_empty<_Alloc>::value,_Vec_base_types<_Ty, _Alloc> >

其中_Vector_alloc又继承了_Vector_val类,_Vector_val有三个指针

	pointer _Myfirst;	// pointer to beginning of array
	pointer _Mylast;	// pointer to current end of sequence
	pointer _Myend;	// pointer to end of array

而_Vector_val类继承了_Container_base类,他有一个指针

	_Container_proxy *_Myproxy;

所以构造一个空vector需要16个字节空间。即sizeof(vector())==16

常用接口

  1. 构造函数:
    默认构造一个空向量,size =0=capacity,push_back操作几次后size开始小于等于capacity
    支持传入一对迭代器,用其界定的区间元素初始化
    支持传入一个对应类型的数组,用以初始化
    vector(n,val) 用n个val初始化

  2. push_back(T &a) 把元素a接入vector尾部
    pop_back(); 把vector尾部元素从向量中剔除。
    _Pop_back_n(n) 从尾部弹出n个元素;
    这一对操作均无返回值,故而要当作栈使用时需要先调用back()成员获取到末尾的元素再执行弹出操作。由于时尾部插入删除,操作时无额外的操作开销。

  3. insert(iterator,val) 从指定位置之前插入val
    insert(iterator,count , val) 从指定位置之前插入count个val
    insert(iterator,iterator_strat,iterator_end);在指定位置之前插入后面一对迭代器之间的所有元素
    erase(iterator) 删除指定位置的元素
    erase(iterator_strat,iterator_end) 删除指定区间的所有元素
    这一对操作会改变后面所有迭代器的值,用了之后不要轻易调用end()成员。

  4. swap(vector<value_type> a) 与同元素类型的vector交换所有元素
    clear()清楚容器中的所有元素。
    [i ]操作符 返回下表i 的引用,可以访问和修改元素值(但是c++建议使用iterator访问元素值)。

  5. assign(count,val) 把count个元素val赋值到容器中
    assign(iterator_start,iterator_end) 把迭代器区间的所有元素赋值到容器中。
    assign操作会清除原容器中的所有内容

  6. resize(n) 将capacity调整为n,如果capacity大于n则删除多余元素,如果capacity小于n则扩容,新增的元素值为val(默认使用类型构造函数,也可以传进去)
    reserve(n) 扩容,如果如果capacity大于n则不做操作,如果capacity小于n则开辟一块可以存放n个元素的空间,将数据拷贝过去。

内存自动增长机制
设置一个数据成员capacity记录当前最多允许存放的元素个数,而size记录当前已经存放的元素个数。当size==capacity的时候立即在找一块足够大的内存空间让capacity翻倍(也有别的扩容策略,不一定是翻倍,但是此策略在扩容时消耗的时间成本总体而言较小,但空间利用率>=50%),把所有元素搬移过去,释放原空间内存。虽然扩容之后物理地址有所改变,却不会出现野指针
STL的做法是设置三个指针记录数据的起始位置,已经存放数据的最后位置,申请的连续内存空间的最后位置。

几个小要点:

  1. vector不提供内置find、sort 成员,可调用标准库find、sort接口内存允许时可以调优先级队列实现选择排序。
  2. 插入删除操作会使之后的迭代器失去原本的指向或者直接失效,当有插入删除操作时要确保迭代器指向不变。
  3. vector是一个c++数据类型,有内置的数据成员,故而村放一个vector所需的内存空间要比存放等数量同类型元素的数组要大。
  4. vector 的迭代器可以与int值相加减,代表将迭代器右移或左移相应位

有序向量的查找算法

二分查找
将向量分为lo mi hi三个部分,mi取作中点,小于当前值则在左侧递归查找,大于则在右侧递归查找。查找失败返回-1(在B-tree等一些数据结构中,查找失败则返回大于不大于它的最后一个元素所在位置<也即如果查找成功它应该在的位置的前一个位置>)
代码实现:

// 二分查找算法:在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
//有多个命中元素时,不能保证返回秩最大者;查找失败时,不能指示失败的位置
template <typename T>  int binSearch ( T* S, T const& e, int lo, int hi ) {
   
   while ( lo < hi ) {
    
      int mi = lo + ( hi - lo ) / 2; 
      if( e < S[mi] ) hi = mi; 
      else if ( S[mi] < e ) lo = mi + 1; 
      else                  return mi; 
   } //成功查找提前终止
   return -1; //查找失败
} 
// 二分查找算法:在有序向量的区间[lo, hi)内查找元素e,0 <= lo <= hi <= _size
//有多个命中元素时,总能保证返回秩最大者;查找失败时,能够返回失败的位置,若需要插入该元素应插入返回值之后的位置(失败时返回值位置可能不可访问,如-1表示应在最前面插入)
template <typename T> int binSearch ( T* S, T const& e, int lo, int hi,bool fail/*指示是否失败,任意值均可*/ ) 
{
   
   while ( lo < hi ) {
    //每步迭代仅需做一次比较判断,有两个分支
      int mi = lo +( hi - lo ) / 2;
      ( e < S[mi] ) ? hi = mi : lo = mi + 1; 
   } //成功查找不能提前终止
   fail = S[ lo - 1 ] != e;
   return lo - 1; 
} 


平均时间复杂度是T(n) = T(n/2) + O(1) = O(lgn) <其实是1.5lgn,对每一次比较,成功只比较1次,失败会比较2次。转向的代价不一导致的比较次数不等而递归深度相同> 
改进每次以黄金分割比比较而不是中点,可继续优化至平均复杂度O(1.44lgn):
//Fibonacci数列类
class Fib {
   
private:
   int f, g; //f = fib(k - 1), g = fib(k)。
public:
   Fib ( int n ) //初始化为不小于n的最小Fibonacci项
   {
    f = 1; g = 0; while ( g < n ) next(); } //fib(-1), fib(0),O(log_phi(n))时间
   int get()  {
    return g; } //获取当前Fibonacci项,O(1)时间
   int next() {
    g += f; f = g - f; return g; } //转至下一Fibonacci项,O(1)时间
   int prev() {
    f = g - f; g -= f; return g; } //转至上一Fibonacci项,O(1)时间
};


 //有多个命中元素时,不能保证返回秩最大者&#x
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值