数据结构(C++) 向量 笔记1

从数组到向量

在这里插入图片描述

  • 向量(vector) 就是线性数组的一种抽象与泛化,它也是由具有线性次序的一组
    元素构成的集合V = { v0, v1, …, vn-1 },其中的元素分别由秩相互区分。
  • 各元素的秩(rank) 互异,且均为[0, n)内的整数。具体地,若元素e的前驱元素共计r个,则其秩就是r。

接口

ADT接口

在这里插入图片描述

动态空间管理

  • 向量实际规模与其内部数组容量的比值(即_size/_capacity) ,亦称作装填因子(load factor) , 它是衡量空间利用率的重要指标。

问题

  • 如何才能保证向量的装填因子既不致于超过1,也不致于太接近于0?
  • 如何实现扩容?新的容量取作多少才算适宜?

解决方法(可扩充向量)

首先解决第一个问题。直接在原有的物理内存空间的基础上追加空间,不现实。数组特定的定址方式,物理空间必须连续,我们无法保证,其尾部总是留有足够的空间供其扩展。
你好
一种可行的方法是如上图所示,申请一个容量足够大的数组,并将原来数组中的数据进行复制,此后便可以插入新元素e而不至于溢出。当然,原数组所占的空间要进行释放交还操作系统。

扩容算法
template <typename T> void Vector<T>::expand() { //向量空间不足时扩容
   if ( _size < _capacity ) return; //尚未满员时,不必扩容
   if ( _capacity < DEFAULT_CAPACITY ) _capacity = DEFAULT_CAPACITY; //不低于最小容量
   T* oldElem = _elem;  _elem = new T[_capacity <<= 1]; //容量加倍
   for ( int i = 0; i < _size; i++ )
      _elem[i] = oldElem[i]; //复制原向量内容(T为基本类型,或已重载赋值操作符'=')
   /*DSA*/ //printf("\n_ELEM [%x]*%d/%d expanded and shift to [%x]*%d/%d\n", oldElem, _size, _capacity/2, _elem, _size, _capacity);
   delete [] oldElem; //释放原空间
}

该程序的关键是,新数组的容量总是取原数组容量的两倍,也正是第二个问题的答案。

缩容算法
template <typename T> void Vector<T>::shrink() { //装填因子过小时压缩向量所占空间
   if ( _capacity < DEFAULT_CAPACITY << 1 ) return; //不致收缩到DEFAULT_CAPACITY以下
   if ( _size << 2 > _capacity ) return; //以25%为界
   T* oldElem = _elem;  _elem = new T[_capacity >>= 1]; //容量减半
   for ( int i = 0; i < _size; i++ ) _elem[i] = oldElem[i]; //复制原向量内容
   delete [] oldElem; //释放原空间
}

注:函数体中上面两行没有看明白,若有小伙伴看到了,麻烦告知一下!!!感谢。

常规向量

直接引用元素

使用访问数组的方式访问向量,可以通过重载操作符[]进行重载。

template <typename T> T & Vector<T>::operator[] ( Rank r ) //重载下标操作符
{ return _elem[r]; } // assert: 0 <= r < _size

置乱算法

C++中round()函数的用法

置乱算法
template <typename T> void permute(Vector<T>& V) { //随机置乱向量,使各元素等概率出现亍殏一位置
 for (int i = V.size(); i > 0; i--) //自后向前
     swap(V[i - 1], V[rand() % i]); //V[i - 1]不V[0, i)中某一随机元素交换
 }
区间治乱接口

在这里插入图片描述

无序查找

  • 无序向量:某种数据类型,仅支持比对,不支持比较的向量,称为无序向量。
顺序查找的算法
template <typename T> //无序向量的顺序查找:返回最后一个元素e的位置;失败时,返回lo - 1
Rank Vector<T>::find ( T const& e, Rank lo, Rank hi ) const { //assert: 0 <= lo < hi <= _size
   while ( ( lo < hi-- ) && ( e != _elem[hi] ) ); //从后向前,顺序查找
   return hi; //若hi < lo,则意味着失败;否则hi即命中元素的秩
}

注:while循环的条件自减什么时候进行,这里有点疑问。
while循环的控制逻辑由两部分组成,首先判断是否已抵达通配符,再判断当前元素与目标元素是否相等。得益于C/C++语言中逻辑表达式的短路求值特性,在前一判断非真后循环会立即终止,而不致因试图引用已越界的秩(-1) 而出错。

插入

插入算法
template <typename T> //将e作为秩为r元素插入
Rank Vector<T>::insert ( Rank r, T const& e ) { //assert: 0 <= r <= size
   expand(); //若有必要,扩容
   for ( int i = _size; i > r; i-- ) _elem[i] = _elem[i-1]; //自后向前,后继元素顺次后移一个单元
   _elem[r] = e; _size++; //置入新元素并更新容量
   return r; //返回秩
}

删除

区间删除
template <typename T> int Vector<T>::remove ( Rank lo, Rank hi ) { //删除区间[lo, hi)
   if ( lo == hi ) return 0; //出于效率考虑,单独处理退化情况,比如remove(0, 0)
   while ( hi < _size ) _elem[lo++] = _elem[hi++]; //[hi, _size)顺次前移hi - lo个单元
   _size = lo; //更新规模,直接丢弃尾部[lo, _size = hi)区间
   shrink(); //若有必要,则缩容
   return hi - lo; //返回被删除元素的数目
}
单元素删除
template <typename T> T Vector<T>::remove ( Rank r ) { //删除向量中秩为r的元素,0 <= r < size
   T e = _elem[r]; //备份被删除元素
   remove ( r, r + 1 ); //调用区间删除算法,等效于对区间[r, r + 1)的删除
   return e; //返回被删除元素
}

唯一化

程序

C++中find函数用法

template <typename T> int Vector<T>::deduplicate() { //删除无序向量中重复元素(高效版)
   int oldSize = _size; //记录原规模
   Rank i = 1; //从_elem[1]开始
   while ( i < _size ) //自前向后逐一考查各元素_elem[i]
      ( find ( _elem[i], 0, i ) < 0 ) ? //在其前缀中寻找与之雷同者(至多一个)
      i++ : remove ( i ); //若无雷同则继续考查其后继,否则删除雷同者
   return oldSize - _size; //向量规模变化量,即被删除元素总数
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值