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) 序列式容器:每个元素的位置取决于元素被插入的时机,被插入时设置的位置,和元素值本身无关。vector、deque、list。 关联式容器:元素位置取决于特定的排序准则,和插入顺序无关。set、multiset、map、multimap。
三、vector 1. 介绍 vector将元素置于一个动态数组中加以管理的容器。vector可以随机存取元素(支持索引值直接存取, 用[]操作符或at()方法)。 vector尾部添加或移除元素非常快速。但在中部或头部插入元素或移除元素比较耗时。 #include <vector> using namespace std; 2. vector对象的默认构造 vector采用模板类实现,vector对象的默认构造形式:vector<T> vecT; 如: vector<int> vint; //一个存放int的vector容器。 vector<float> vFloat; //一个存放float的vector容器。 vector<string> vString; //一个存放string的vector容器。 ... //尖括号内还可以设置指针类型或自定义类型。 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 == itB,itA != itB 其中list,set,multiset,map,multimap支持双向迭代器。 2.随机访问迭代器支持的操作 在双向迭代器的操作基础上添加 it+=i, it-=i, it+i(或it=it+i),it[i], itA<itB, itA<=itB, itA>itB, itA>=itB 的功能。 其中vector,deque支持随机访问迭代器。 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 的只读形式,使用这两种迭代器时,不会修改到容器中的值。 备注:不过容器中的insert和erase方法仅接受这四种类型中的iterator,其它三种不支持。《Effective STL》建议我们尽量使用iterator取代const_iterator、reverse_iterator和const_reverse_iterator。
五、vector对象 1. 带参数构造 vector(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。注意该区间是左闭右开的区间。 vector(n,elem); //构造函数将n个elem拷贝给本身。 vector(const vector &vec); //拷贝构造函数。 2. 赋值 vector.assign(beg,end); //将[beg, end)区间中的数据拷贝赋值给本身。注意该区间是左闭右开的区间。 vector.assign(n,elem); //将n个elem拷贝赋值给本身。 vector& operator=(const vector &vec); //重载等号操作符 vector.swap(vec); // 将vec与本身的元素互换。 3. 大小 vector.size(); //返回容器中元素的个数(不是最后一位的位置) vector.empty(); //判断容器是否为空 vector.resize(num); //重新定义容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 vector.resize(num, elem); //和上面那条类似,重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 举例:vInt是vector<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位置插入n个elem数据,无返回值。 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 下一篇STL-string
文章分类:
算法学习
|