Datahub
数据改变生活

STL-vector

发表时间:2022-10-28 23:26

一、模板的介绍

模板是实现代码重用机制的一种工具,实质就是实现类型参数化,即把类型定义为参数。

C++提供两种模板:函数模板,类模板。

1.函数模板

    先看几个求最大值的函数。

int max(int a,int b){

return a > b ? a : b;
}

float max(float a,float b){

   return a > b ? a : b;

}

char max(char a,char b){

   return a > b ? a : b;

}

函数模板就是建立一个通用的函数,其函数返回类型和形参类型用虚拟的类型来代表。

凡是函数体相同的函数都可以用函数模板来代替,不必定义多个函数,(如下列例子中一个函数实现了上述几种函数的功能)只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

template<typename T>     //或者   template<class T>

T max(T a, T b){ // 这个函数实现了上面所有函数的用法

return a>b? a:b;

}

void main(){

   int iMax = max(3,5);    //调用int max(int a, int b);

   char chMax = max('w','d');      //调用char max(char a, char b);

   float fMax = max(2.7f, 1.3f);   //调用float max(float a, float b);

}

2. 类模板

类模板就是建立一个通用类,其数据成员的类型、成员函数的返回类型和参数类形都可以不具体指定,而用虚拟的类型来代表。当使用类模板建立对象时,系统会根据实参的类型取代类模板中的虚拟类型,从而实现不同类的功能。

下方求最大值的类模板作用和函数模板相同。

class CMax{

   public:

CMax(int a, int b){

m_a = a;

m_b = b;

}

int GetMax(){

return m_a>m_b? m_a:m_b;

}

private:

int m_a;

int m_b;

}

template<typename T>     //或者   template<class T>

class CMax{

public:

CMax(T a, T b){

m_a = a;

m_b = b;

}

T GetMax(){

return m_a>m_b? m_a:m_b;

}

private:

T m_a;

T m_b;

};

void main(){

CMax<int> maxInt(3,5);   //需要指定类型

int iMax = maxInt.GetMax();

CMax<char> maxChar('w','d');

char chMax = maxChar.GetMax();

CMax<float> maxFloat(2.7f,1.3f);

float fMax = maxFloat.GetMax();

}

可以定义多种类型的形参。

template<typename T1, typename T2>

class CTest

{...};

对象实例化时:

CTest testA<int, float>;

CTest testB<double, string>

二、容器

1. 简介

容器是用来存放、管理一组元素的数据集合。以下是部分容器的数据结构:

2. 分类

容器有序列式容器(Sequence containers)和关联式容器(Associated containers

序列式容器:每个元素的位置取决于元素被插入的时机,被插入时设置的位置,和元素值本身无关。vectordequelist

关联式容器:元素位置取决于特定的排序准则,和插入顺序无关。setmultisetmapmultimap

三、vector

1. 介绍

vector将元素置于一个动态数组中加以管理的容器。vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法)。

vector尾部添加或移除元素非常快速。但在中部或头部插入元素或移除元素比较耗时

#include <vector>   

using namespace std;

2. vector对象的默认构造

vector采用模板类实现,vector对象的默认构造形式:vector<T> vecT;   如:

vector<int> vint;            //一个存放intvector容器。

vector<float> vFloat;     //一个存放floatvector容器。

vector<string> vString;     //一个存放stringvector容器。

...     //尖括号内还可以设置指针类型或自定义类型。

Class CA{};

vector<CA*> vpCA;    //用于存放CA对象的指针的vector容器。

vector<CA> vCA;     //用于存放CA对象的vector容器。由于容器元素的存放是按值复制的方式进行的,所以此时CA必须提供CA的拷贝构造函数,以保证CA对象间拷贝正常。

3. 末尾操作

vector.push_back(e); //在容器尾部加入一个元素。

vector.pop_back();              //移除容器中最后一个元素

例如:   vector<int>   v;

              v.push_back(1); v.push_back(3);

         vt.push_back(5);v.push_back(7);

               v.push_back(9);

此时容器v就包含了按顺序的1,3,5,7,9元素。

如果在此基础上再运行语句v.pop_back();

v.pop_back();此时容器v就包含了按顺序的1,3,5元素。

4. 数据存储

vec.at(id);   //返回索引id所指的数据,如果id越界,抛出out_of_range异常。

vec[id];   //返回索引id所指的数据,越界时,运行直接报错。

例如:

假设vInt是用vector<int> 声明的,且已包含按顺序的1,3,5,7,9;此时vInt.at(2)==vInt[2]==5。若运行代码vInt.at(2)=8,或者运行vInt[2]=8,则vInt就包含按顺序的1,3,8,7,9值。

vector.front();   //返回第一个数据。

vector.back();   //返回最后一个数据。

vector<int> vInt; //假设包含{1,3,5,7,9}

int iF = vector.front(); //iF==1

int iB = vector.back(); //iB==9

vector.front() = 121; //vecInt包含{121,3,5,7,9}

vector.back() = 129; //vecInt包含{121,3,5,7,129}

四、迭代器

迭代器是一个遍历STL容器内全部或部分元素的对象。指出容器中的一个特定位置(指向一个元素),如同一个指针。迭代器提供对一个容器中的对象的访问方法,并且可以定义了容器中对象的范围。

输入迭代器:只读迭代器,从容器中读取元素,只能一次读入一个元素并且向前移动,只支持一遍算法,同一个输入迭代器不能重复遍历一个序列。

输出迭代器:只写迭代器,往容器中写入元素,只能一次写入一个元素并且向前移动,只支持一遍算法,同一个输出迭代器不能重复遍历一个序列。

正向迭代器:组合输入迭代器和输出迭代器的功能,还可以多次解析一个迭代器指定的位置,可以对一个值进行多次读/写。

双向迭代器:组合正向迭代器的功能,还可以通过--操作符向后移动位置。

随机访问迭代器:组合双向迭代器的功能,还可以向前向后跳过任意个位置,可以直接访问容器中任何位置的元素。

p+=i:使得 p 往后移动 i 个元素。

p-=i:使得 p 往前移动 i 个元素。

p+i:返回 p 后面第 i 个元素的迭代器。

p-i:返回 p 前面第 i 个元素的迭代器。

p[i]:返回 p 后面第 i 个元素的引用。

上两种是最基础的迭代器,后三种是上面几种迭代器和其他功能的组合。

1.双向迭代器支持的操作

it++,   ++it, it--, --it*it取迭代器内的内容itA = itB

itA == itBitA != itB

其中list,set,multiset,map,multimap支持双向迭代器。

2.随机访问迭代器支持的操作

在双向迭代器的操作基础上添加

it+=iit-=iit+i(it=it+i)it[i],

itA<itB,   itA<=itB,   itA>itB,   itA>=itB   的功能。

其中vectordeque支持随机访问迭代器。

3. vector与迭代器配合使用

vec.begin();   //返回容器中第一个元素的迭代器。

vec.end();   //返回容器中最后一个元素之后的迭代器。

例如:vInt是用vector<int>声明的容器,假设已经包含了按顺序的1,3,5,7,9元素。

vector<int>::iterator it;   //声明容器vector<int>的迭代器。

运行 it=vInt.begin();    //此时*it==1

运行++it;   // 或者it++;   此时*it==3

//++的效率比后++的效率高,因为++返回引用,后++返回值。

运行it += 2;   //此时*it==7

运行it = it +1;   //此时*it=9

运行++it;   //此时it==vInt.end();   此时不能再执行*it

vec.rbegin();   //返回容器中倒数第一个元素的迭代器。

vec.rend();   //返回容器中倒数最后一个元素之后的迭代器。

正向遍历:

for(vector<int>::iterator it=vInt.begin(); it!=vInt.end(); ++it){

      int iItem = *it;

      cout << iItem;    //或直接使用   cout << *it;

}

这样子便打印出1 3 5 7 9

逆向遍历:

for(vector<int>::reverse_iterator rit=vInt.rbegin(); rit!=vInt.rend(); ++rit){    //注意,小括号内仍是++rit

int iItem   = *rit;

      cout << iItem; //或直接使用cout << *rit;

}

此时将打印出9,7,5,3,1

注意,这里迭代器的声明采用vector<int>::reverse_iterator,而非vector<int>::iterator

rend指向最前面的元素之前的元素,end指向最后的元素之后的元素。

迭代器还有其它两种声明方法:

vector<int>::const_iterator

vector<int>::const_reverse_iterator

这两种分别是

vector<int>::iterator

vector<int>::reverse_iterator

的只读形式,使用这两种迭代器时,不会修改到容器中的值。

备注:不过容器中的inserterase方法仅接受这四种类型中的iterator,其它三种不支持。《Effective STL》建议我们尽量使用iterator取代const_iteratorreverse_iteratorconst_reverse_iterator

五、vector对象

1. 带参数构造

vector(beg,end);    //构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间。

vector(n,elem);   //构造函数将nelem拷贝给本身。

vector(const vector &vec);   //拷贝构造函数。

2. 赋值

vector.assign(beg,end);    //[beg, end)区间中的数据拷贝赋值给本身。注意该区间是左闭右开的区间。

vector.assign(n,elem);   //nelem拷贝赋值给本身。

vector& operator=(const vector   &vec); //重载等号操作符

vector.swap(vec);   // vec与本身的元素互换。

3. 大小

vector.size();    //返回容器中元素的个数(不是最后一位的位置)

vector.empty();    //判断容器是否为空

vector.resize(num);   //重新定义容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

vector.resize(num, elem);   //和上面那条类似,重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

举例:vIntvector<int>   声明的容器,现已包含1,2,3元素。

vInt.resize(5);   //此时里面包含1,2,3,0,0元素。

vInt.resize(7,4);   //此时里面包含1,2,3,0,0,4,4元素。

vInt.resize(1);   //此时里面包含1元素。

4. 插入

vector.insert(pos,elem);   //pos位置插入一个elem元素的拷贝,返回新数据的位置。

vector.insert(pos,n,elem);   //pos位置插入nelem数据,无返回值。

vector.insert(pos,beg,end);   //pos位置插入[beg,end)区间的数据,无返回值。

5. 删除

vector.clear(); //移除容器的所有数据

vec.erase(beg,end);   //删除[beg,end)区间的数据,返回下一个数据的位置。

vec.erase(pos);    //删除位置pos的数据,返回下一个数据的位置。

举例vInt是用vector<int>声明的容器,现已包含按顺序的1,3,5,6,9元素。

vector<int>::iterator itBegin=vInt.begin()+1;

vector<int>::iterator itEnd=vInt.begin()+3;

vInt.erase(itBegin,itEnd);

//3,5被删除。此时容器vecInt包含按顺序的1,6,9三个元素。

参考资料:

http://c.biancheng.net/cpp/biancheng/cpp/rumen_14/

https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html

https://baike.baidu.com/item/%E8%BF%AD%E4%BB%A3%E5%99%A8/3803342?fr=aladdin

http://c.biancheng.net/view/338.html


文章分类: 算法学习
分享到:
QQ:258506508                                     联系电话:020-000000    000-000000                                   联系邮箱:xxx@.co.m                                     联系地址:XXX省XXX市XXX县XXX路