模版:模版使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现,方便了大规模的软件开发。
一般形式:
template<类型形式参数表>
返回类型 FunctionName(形式参数表)
{
//函数定义体
}
绝对值的模版:
#include<iostream>
using namespace std;
<span style="background-color: rgb(255, 204, 255);">template<typename T>
T abs(T x)
{
return x<0?-x:x;
}</span>
int main()
{
int a=-5;
int b=6;
cout<<abs(a)<<endl;
cout<<abs(b)<<endl;
return 0;
}
模版作用:
使用类模版使用户为类声明一种模式,使得类中的某些数据成员,某些成员函数的参数,某些成员函数的返回值,能取任意类型(包括基本类型和用户自定义类型)。
类模版定义:
template<模版参数表>
class 类名
{类成员声明}
在类模版以外定义其成员函数:
template<模版参数表>
类型名 类名<T>::函数名(参数表)
类模版与模版类区别:
类模版是模版的定义,不是一个实实在在的类,定义中用到的通用类型参数。
模版类是实实在在的类定义,是类模版的实例化,类定义中参数被实际类型所代替。
模版实现:
模版定义很特殊,由template<...>处理的任何东西都以为着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模版实例告知。所以为了容易使用,几乎总是在头文件中放置全部的模版声明和定义
将程序写的尽可能通用
将算法从特定的数据结构中抽象出来,成为通用的
c++的模版为泛型程序设计奠定了关键的基础
STL是泛型程序设计的一个范例
容器(container)
迭代器(iterator)
算法(algorithms)
函数对象(function object)
容器类是容纳,包含一组元素或元素集合的对象
七种基本容器:
向量(vector)
双端队列(deque)
列表(list)
集合(set)
多重集合(multiset)
映射(map)
多重映射(multimap)
容器接口:
通用容器运算符
== , != ,> , >= , < , <= ,=
方法(函数)
迭代方法:
begin(),end(),rebegin(),rend()
访问方法:
size(),max_size(),swap(),empty()
顺序容器的接口
插入方法
push_front(), push_back(), insert(), 运算符“=”
删除方法
pop(), erase() clear()
其他顺序容器访问方法(不锈钢访问方法)
front() back() 下标[ ] 运算符
vector使用:
初始化vector容器方法
1:vector<elementType > v ; //创建一个没有任何元素的空容器
2:vector<elementType > v(other Vec); //调用拷贝构造函数创建新容器
3:vector<elementType > v(size); //创建一个大小为size的对象v,并使用默认构造函数初始化该向量
4:vector<elementType > v(n,elem); //创建一个大小为n的容器,并使用元素elem初始化每一个元素
5:vector<elementType > v(begin,end);//创建容器v,并使用(begin,end)之间的元素初始化容器
元素的插入
1:veclist.push_back(elem);//将elem的一个拷贝插入到veclist的末尾
2:veclist.insert(position,elem);//将elem的一个拷贝插入到指定的position位置上
3:veclist.insert(position,n,elem);//将elem的n个拷贝插入到由position指定的位置上
4:veclist.insert(position,beg,end);//将从迭代器beg至end-1之间的元素插入到veclist的position位置上
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
vector<int> num; //STL中的vector容器
int element;
while(cin>>element) //一直输入,知道输入的是非整数数据为止
{
num.push_back(element); //添加到容器末尾
}
for(int i=0;i<num.size();i++) //访问容器内的元素
{</span>
cout<<num[i]<<endl;
}
return 0;
}
</pre><p>迭代器是面向对象版本的指针</p><p><span style="white-space:pre"></span>指针可以指向内存中的一个地址</p><p><span style="white-space:pre"></span>迭代器可以指向容器中的一个位置</p><p>STL的每一个容器类模版中,都定义了一组对应的迭代器类</p><p>使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型</p><p></p><p>vector<int>::iterator iter:</p><p><span style="white-space:pre"> </span>这条语句定义了一个名为iter的变量,它的数据类型是由vector<int>定义的iterator类型。</p><p>begin和end 操作</p><p><span style="white-space:pre"> </span>如果容器中有元素的话,由begin返回的迭代器指向第一个元素:</p><p><span style="white-space:pre"> </span>vector<int>::iterator iter=ivec.begin();</p><p><span style="white-space:pre"> </span>由end操作返回的迭代器指向vector的“末端元素的下一个”。通常称为超出末端迭代器(off-the-end iterator)。</p><p></p><p>访问vector 容器中的内容</p><p><span style="white-space:pre"> </span><pre name="code" class="objc">for(vector<int>::size_type ix=0;ix!=ivec.size();++ix)
{
cout<<ivec[ix]<<endl; <span style="color:#ff0000;">//用下标方式访问</span>
}
for(vector<int>::iterator iterator=ivec.begin();iter!=ivec.end();++iter)
{
cout<<*iter<<endl; <span style="color:#ff0000;">//用iterator访问</span>
}
vector迭代器的自增和解引用运算
for(vector<int>::size_type ix=0;ix!=ivec.size();++ix)
{
ivec[ix]=0; <span style="color:#ff0000;">//用下标方式将vector所有元素清0</span>
}
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter)
{
*iter=0; <span style="color:#ff0000;">//将iterator指向的元素设为0</span>
}
容器的反向遍历
反向遍历是使用迭代器 reverse_iterator
vector<int>::reverse_iterator ri:
rbegin. rend
反向遍历时使用rbegin,rend来定位
反向遍历迭代器的使用与普通的迭代器一样,可以使用++在位移迭代器,使用*运算符来取元素
vector<int>::reverse_iterator ri=num.rbegin();
while(ri!=num.rend())
{
cout<<*ri<<" ";
ri++;
}
cout<<endl;
const_iterator
该类型只能访问容器内元素,但不能改变其值
for(vector<string>::const_iterator iter=text.begin();iter!=text.end();++iter)
{
cout<<*iter<<endl;
}
对const_iterator类型解引用时,则可以得到一个指向const对象的引用,如同任何常量一样,该对象不能进行重写
不要把const_iterator对象与const的iterator对象混淆起来,const的iterator不能做自增减,但可以对它指向的元素赋值
元素的删除
1.veclist.clear() //清空容器内的所有元素
2.veclist.erase(position)//删除position指定位置的元素
3.veclist.erase(beg,end)//删除beg至end-1直接的元素
4.veclist.pop_back()//删除最后一个元素
vector<int>::iterator iter=num.begin();
num.pop_back(); <span style="color:#ff0000;">//删除最后一个元素</span>
num.erase(iter); <span style="color:#ff0000;">//删除容器的第一个元素</span>
num.erase(iter,iter+2); <span style="color:#ff0000;">//删除前2个元素</span>
其他常用函数
1.veclist.capacity();//返回当前可插入到容器veclist的最大数
2.veclist.empty();//判断容器是否为空,为空返回true,否则返回false
3.veclist.size()//判断容器veclist中当前元素个数
4.veclist.max_size()//返回可以插入到容器中元素的最大元素数(可以理解为无穷大)
初始化list容器方法
list容器类有四种形式构造函数
list<elementType> L; <span style="white-space:pre"> </span><span style="color:#ff0000;">//构造空容器L</span>
list<elementType> L(n,elem); <span style="color:#ff0000;">//创建一个大小为size的对象L,并使用elem元素进行初始化</span>
list<elementType> L(list1); <span style="color:#ff0000;">//创建容器L,并使用已创建的容器list1进行初始化</span>
list<elementTYpe> L(begin,end);<span style="color:#ff0000;"> //创建容器L,并使用(begin,end)之间的元素初始化容器</span>
元素的插入
L.push_back(elem); <span style="color:#ff0000;">//向容器的末尾插入元素elem的拷贝</span>
L.push_front(elem); <span style="color:#ff0000;">//向容器的开端插入元素elem的拷贝</span>
L.insert(position,elem); <span style="color:#ff0000;">//向容器的position位置插入元素elem的拷贝</span>
L.insert(position,n,elem); <span style="color:#ff0000;">//向容器的position位置插入元素elem的n个拷贝</span>
L.insert(position,beg,end); <span style="color:#ff0000;">//将迭代器beg至end-1指向的内容插入到容器的position位置上</span>
L.splice(position,list); <span style="color:#ff0000;">//将链表容器list中的元素插入到position位置上,并且清空list容器</span>
L.splice,(position,list,pos); <span style="color:#cc0000;">//将容器list中的pos位置上的元素插入到position位置上,并将pos位置上的元素从list中移除</span>
L.splice(position,list,beg,end); <span style="color:#ff0000;">//将容器list中beg至end-1位置上的元素插入到position位置上,并将这些元素从list中移除</span>
元素的删除
L.pop_back(); <span style="color:#ff0000;">//删除容器的最后一个元素</span>
L.pop_front(); <span style="color:#ff0000;">//删除容器的第一个元素</span>
L.clear(); <span style="color:#ff0000;">//删除容器的所有元素</span>
L.erase(position); <span style="color:#ff0000;">//删除容器指定位置的元素</span>
L.erase(beg,end); <span style="color:#ff0000;">//删除迭代器beg至end-1之间的元素</span>
L.remove(elem); <span style="color:#ff0000;">//删除与元素elem相等的元素</span>
例:
#include<list>
#include<iostream>
using namespace std;
int main()
{
list<int> Link; <span style="color:#ff0000;">//构造一个列表用于存放整数列表</span>
for(int i=0;i<10;i++)
{
Link.push_front(i); <span style="color:#ff0000;">//在列表开端插入i</span>
}
Link.insert(Link.end(),10); <span style="color:#ff0000;">//使用insert在末尾插入数据</span>
Link.remove(5); <span style="white-space:pre"> </span><span style="color:#ff0000;">//删除5</span>
list<int>::iterator p=Link.begin(); /<span style="color:#ff0000;">/迭代子p用于便利链表</span>
while(p!=Link.end())
{
cout<<*p<<" ";
p++; <span style="white-space:pre"> </span><span style="color:#ff0000;">//p指向下一个节点</span>
}
return 0;
}
<span style="background-color: rgb(192, 192, 192);">skywalker@skywalker:~/work$ ./a.out
9 8 7 6 4 3 2 1 0 10 </span>
queue应用举例
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
int main()
{
stack<int> st; <span style="color:#ff0000;">//堆</span>
queue<int> q; <span style="color:#ff0000;">//队列</span>
st.push(1); <span style="color:#ff0000;">//压入1</span>
st.push(2); <span style="color:#ff0000;">//压入2</span>
st.push(3);
q.push(100); <span style="color:#ff0000;">//queue和stack都有push操作</span>
q.push(200);
cout<<st.top()<<endl;
st.pop();
cout<<st.top()<<endl;
cout<<q.front()<<endl;
q.pop();
cout<<q.front()<<endl;
while(!st.empty()) <span style="white-space:pre"> </span><span style="color:#ff0000;">//当然queue也能这样用</span>
{
int a=st.top();
cout<<a<<endl;
st.pop();
}
}
<span style="background-color: rgb(192, 192, 192);">skywalker@skywalker:~/work$ ./a.out
3
2
100
200
2
1</span>
map容器
map是STL的一个关联容器,它提供一对一的数据处理能力其中第一个可以称为关键字,每个关键字只能在map中出现一次
第二个可以称为该关键字的值
map内部所有的数据都是有序的,后边我们会见识到有序的好处
map容器构造
map<elemType,elemType>m://创建空容器
map<elemType,elemType>m(m1);//调用拷贝构造函数来创建容器
map<elemType,elemType>m(beg,end);//使用迭代器beg至end-1区间的数据初始化容器
map<elemType,elemType,greator<const int>>m(beg,end,greater<const int>());//使用迭代器beg至end-1区间的数据和指定的比较函数greater来创建对象
map元素插入
1:用insert函数插入pair数据
2.用insert函数插入value_type数据
3.用数组方式插入数据
以上三种方式都可以插入数据,但是他们是有区别的,其中第一种和第二种在效果上的完成时是一样的,用insert函数插入数据时涉及到集合的唯一性概念,即map中有这个关键字时,insert的操作会失败。而用数组方式插入时,若有这个关键字,它会覆盖以前的关键字对应的值。
insert函数
insert函数的返回值为pair类型,pair容器的第一个类型为当前map容器的迭代器类型,表示元素插入到map容器中的位置,第二个类型为bool类型,表示insert操作是否成功,成功返回true,失败为false
pair<map<int,string>::iterator,bool> insert_pair;
insert_pair=mapStudent.insert(map<int,string>::value_type(1,"student_one"));
map元素访问
1.使用正向迭代器map<elemType,elemType>::iterator 使用begin,end 函数操作
2.使用反向迭代器map<elemType,elemType>::reverse_iterator 使用rbegin,rend函数操作
3.使用常迭代器map<elemType,elemType>::const_iterator 使用begin,end函数操作,但是只能访问,不能修改元素
注:由于map容器的元素是通过转换为pair对象插入到容器中的,因此,要通过pair对象的first和second变量指示出来
map<int,string>::iterator iter;
for(iter=mapStudent.begin();iter!=mapStudent.end();iter++)
{
cout<<iter->first<<" :"<<iter->second<<endl;
}
map元素删除
1.m.clear(); //删除容器中所有元素
2.m.erase(position); //删除迭代器position位置的元素
3.m.erase(elem); //删除与关键字elem相等的元素
4.m.erase(beg,end); //删除迭代器beg至end-1范围的元素
数据的查找(包括判定这个关键字是否在map中出现)
1.用count函数来判定关键字是否出现
2.用find函数来定位数据出现位置,它返回的是一个迭代器,当数据出现时,它返回数据所在位置的迭代器,如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器
iter=mapStudent.find();
if(iter!=mapStudent.end())
{ //..... }
3.Equal_range函数返回一个pair,pair里面第一个变量是lower_bound返回的迭代器,pair里面返回第二个迭代器是upper_bound返回的迭代器,如果这两个迭代器相等的话,则说明map中不存在这个关键字。
#include<map>
#include<string>
#include<iostream>
using namespace std;
int main()
{
map<int,string>mapStudent;
mapStudent.insert(pair<int,string>(1,"student_one")); <span style="color:#ff0000;">//第一种插入方法</span>
mapStudent.insert(pair<int,string>(1,"student_one1"));
mapStudent.insert(map<int,string>::value_type(2,"student_two")); <span style="color:#ff0000;">//第二种插入方法</span>
mapStudent[3]="student_three"; <span style="color:#ff6600;">//第三种插入方法</span>
mapStudent[3]="student_three1";
pair<map<int,string>::iterator,bool>Insert_pair; <span style="color:#ff0000;">//用来查看是否插入成功</span>
Insert_pair=mapStudent.insert(pair<int,string>(4,"student_four"));
if(Insert_pair.second==true)
{
cout<<"Insert Successfully"<<endl;
}
else
{
cout<<"Insert Failure"<<endl;
}
map<int,string>::iterator iter;
for(iter=mapStudent.begin();iter!=mapStudent.end();iter++) <span style="background-color: rgb(255, 255, 255);"><span style="color:#ff0000;">//用来打印</span></span>
{
cout<<iter->first<<":"<<iter->second<<endl;
}
iter=mapStudent.find(1); <span style="color:#ff0000;">//用来查找</span>
if(iter!=mapStudent.end())
{
cout<<"Find ,the value is :"<<iter->second<<endl;
}
else
{
cout<<"DO not Find "<<endl;
}
iter=mapStudent.find(5); //用来查找
if(iter!=mapStudent.end())
{
cout<<"Find ,the value is :"<<iter->second<<endl;
}
else
{
cout<<"DO not Find "<<endl;
}
}
<span style="background-color: rgb(204, 204, 204);">skywalker@skywalker:~/work$ ./a.out
Insert Successfully
1:student_one
2:student_two
3:student_three1
4:student_four
Find ,the value is :student_one
DO not Find </span>