原文链接:http://blog.csdn.net/wangfengwf/article/details/11580989#t9
作为C++标准库相当重要的一部分,STL库提供一系列组件操作。它主要可以分为容器、迭代器、基本算法、函数对象以及内存分配器和配接器六个部分。整个STL库的代码都采用模板函数以及模板类的方式实现,具有高度的通用性。对于传统的应用程序来讲,模板库支持并且倡导一种新的编程风格,即称为泛型编程思想,以通用的模板方式来编写应用程序中的数据结构与算法。
C++标准STL库中封装实现了常见数据结构,并以容器的方式提供给用户使用。STL容器主要包含vector向量、deque队列、list链表、set集合与map映射等。每个类别容器相应通过一个模板类对外提供操作接口。通过提供的容器类类型,开发者可以自定义封装实现相应的数据结构类的对象。通过定义时传入真正的数据类型来实例化产生对应容器类的对象实例,并且在外部通过这些类提供的方法接口来实现应用程序中需求处理功能。
STL模板库容器大致可以分为两类:一类是以线性组织方式存储类型相同的对象的序列式容器,另一类是使用树结构的关联式容器。
1.序列式容器
序列式容器在STL中主要包含常见的三种:向量vector、链表list和双端队列deque。
q 向量vector为一种顺序存储同类型元素的数据结构。它是一种数组方式的思路实现,并且可以随机访问的序列。
q 链表list是一种实现双向链表数据结构的容器。它只支持顺序访问序列中的元素。该容器在删除、插入相应元素时,效率较高。另外,list可以与vector一样在需要时动态改变其大小。
q 双端队列deque是类似向量的一种队列结构。它允许在该队列的头部和尾部插入并且删除相应的元素。同时,它也支持针对其元素的顺序以及随机访问。
2.关联式容器
关联式容器则是采用了key-value键值的方式存储和访问容器中的元素。关联式容器采用树结构组织数据,支持快速、随机并且高效的检索其中的元素。关联式容器主要包含set、multiset、map以及multimap容器。
q set容器支持随机存取,并且其键与对应的数据元素为同一个值。该容器中所有的元素必须是唯一的,不能包含重复的元素。
q multiset容器则在set基础上可以包含重复的元素。同样,该容器的键与对应的元素也是为同一值。
q map是一个包含键值对的容器。该结构中存放的键为索引使用的关键字,而对应的值则为真正存放的数据。该容器允许存在重复的键值,但每个键只能与一个值相互对应。
q multimap提供单个关键词可以对应多个数据的数据结构操作,供实际应用中选择使用。
顺序式容器与关联式容器在底层实现,通过不同的数据结构类型来区分。针对提供的不同的操作接口,用户并不需要了解具体容器底层实现,可以直接通过对外公布的接口访问对应的数据元素。而容器的设计实现则是主要基于数组、链表以及二叉树基本数据结构原型的底层实现。开发者通常只需要了解容器的基本功能以及应用场合,就能够在实际应用中选择合适的容器来处理相应的数据。
vector向量容器的数据结构的原型为数组类型。只不过该容器通过封装实现vector模板类实现动态数组结构,并提供基于该顺序存储结构的操作接口供开发者调用。vector容器在使用时,必须包含相应的头文件(#include<vector>)。头文件提供了相应的操作接口声明。一旦包含之后,就可以定义vector对象实例存储并操作相应类型的数据元素。
由于vector为模板类,所以在实际定义vector对象时,需要指定该模板类型参数。而相应的模板参数可以是内置数据类型,也可以是自定义的结构体、类等类型。例如,以下代码根据传入的实际类型来确定该vector实例化存储相应的类型元素。
#include<vector>
std::vector;
vector<string>stringValue; //第一个定义string标准字符串类型的vector对象stringValue
vector<int> intValue; //第二个定义int整型类型的vector对象intValue
vector<float> floatValue(5,6.0); //第三个定义float浮点类型的vector对象floatValue
vector<MyString>MyStringValue(5); //第四个定义自定义字符串操作MyString类型的vector对象MyStringValue
上述代码中,标准的库都采用std名字空间,使用相应的标准库的中类型操作。一个应用程序需要使用标准名字空间内的API,需要先声明在该名称空间下。std::vector表明使用的是std名字空间下的该类。通常情况下,建议使用全局方式定义std名字空间。即使用using namespace std;语句来公开表示以下应用程序中使用的标准库操作都来自于该名字空间。
实例中主要根据具体的参数类型,采用vector类提供的构造函数来构造实例化对象。根据vector类提供的对外构造函数接口,可以采用不同的构造函数来构造该容器类对象实例。
q 第一个stringValue对象为定义string类型的空vector。该容器是个模板实现,其中存放的元素必须为相应传入模板实例化的参数类型,即上述语句主要定义空的可以存放string类型元素的vector向量。
q 第二个则同样定义一个空vector对象,该对象中存放着整型元素。
q 第三个实例对象的定义是根据vector类提供的另一个构造函数接口而来。该构造函数结构接口对象定义语法为vector<Type> objectName(size,value),即定义vector对象实例同时指定初始化元素的大小以及对应存放的值。实例三中实际定义了vector对象floatValue,该向量存放float浮点型数据元素,并且在构造时指定其大小为5,同时每个元素都采用数据值6.0来初始化。
q 第四个实例中则直接通过自定义字符串类型MyString作为实例化参数类型,定义指定大小为5个元素的向量MyStringValue。
vector向量在模板库中既然以类方式实现,那么除了提供对应的构造函数用于定义具体vector对象实例外,还提供了相当丰富的对外操作vector向量的公开接口方法。这些方法主要用于数据元素的操作,如表16.1所示。
表16.1 向量vector接口方法说明
接口方法名称 |
基本功能说明 |
vectorObject.assign(start,end) |
将迭代器start与end之间的数据元素赋值给vectorObject |
vectorObject.assign(n, elem) |
将n个elem元素赋给其调用的vectorObject |
vectorObject.at(index) |
返回向量vectorObject中指定索引index所指的数据元素 |
vectorObject.back() |
返回向量vectorObject中最后一个数据元素 |
vectorObject.begin() |
返回指向向量vectorObject中第一个元素的迭代器 |
vectorObject.capacity() |
返回向量vectorObject中元素的个数 |
vectorObject.clear() |
清空向量vectorObject中的数据元素 |
vectorObject.empty() |
判断向量vectorObject是否为空,为空则返回true值 |
vectorObject.end() |
返回指向向量vectorObject最后一个数据元素的迭代器 |
vectorObject.erase(loc) |
删除当前向量loc位置数据元素,返回下一个数据元素位置 |
vectorObject.erase(start,end) |
删除从start到end区间的元素,包含start不包含end,并返回下一个数据元素位置 |
vectorObject.front() |
返回向量中第一个数据元素 |
vectorObject.insert(pos,elem) |
当前向量中pos位置插入元素elem,并返回新数据的位置 |
vectorObject.insert(pos,n,elem) |
当前向量中pos位置插入n个elem数据元素,不返回任何值 |
vectorObject.insert(pos,start,end) |
当前向量中pos位置处插入区间在start到end之间的数据元素,包含start但不包含end,无任何返回值 |
vectorObject.max_size() |
返回当前向量中最大数据量,即向量的最大长度 |
vectorObject.pop_back() |
删除当前向量最后一个数据元素 |
vectorObject.push_back(elem) |
当前向量尾部添加一个数据元素 |
vectorObject.rbegin() |
返回一个逆向队列的第一个数据元素 |
vectorObject.rend() |
返回一个逆向队列的最后一个数据元素 |
VectorObject.reserve() |
设置当前向量合适的最小容量 |
vectorObject.resize(num) |
重新设定当前向量的长度 |
vectorObject.size() |
返回当前容器中实际数据元素个数 |
v1.swap(v2) |
呼唤向量v1与v2的数据元素 |
operator[] |
重载下标操作符,用于访问指定向量中的元素 |
下面将会通过一个完整的实例,调用vector相应的接口,操作vector存储的数据。代码编辑如下所示。
1.准备实例
打开UE工具,创建新的空文件并且另存为chapter1601.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1601
* 源文件chapter1601.cpp
* vector基本操作实例
*/
#include <iostream>
#include <vector>
using namespace std;
int main()
{
//第一部分代码
vector<int> intValue; //定义int整型类型的vector对象intValue
vector<int>::iterator iter; //定义int整型类型的迭代器对象iter
vector<int>::iterator tempIter; //定义int整型类型的迭代器对象tempiter
for(int i = 0;i < 10;i++) //定义for循环控制结构,从变量i值为0开始,循环10次
{
intValue.push_back(i); //控制结构内实现将i变量递增值逐个放入容器intValue中
}
cout<<"intValue size:"<<intValue.size()<<endl; //通过vector提供的size()方法计算该容器内元素个数
//第二部分代码
cout<<"intValueelement:";
for(int i = 0;i < intValue.size();i++) //for循环内,通过vector的at方法逐个访问输出元素
{
cout<<intValue.at(i)<<" ";
}
cout<<endl;
//第三部分代码
intValue.assign(5,6); //通过vector的assign方法来实现容器内元素值的替换
cout<<"intValue element:";
for(int i = 0;i < intValue.size();i++) //通过for循环控制结果循环打印输出容器内元素值
{
cout<<intValue.at(i)<<" ";
}
cout<<endl;
//第四部分代码
iter = intValue.begin(); //通过begin()方法将迭代器指向容器intValue第一个元素
intValue.insert(iter,100); //通过vector的insert方法将迭代器指向的元素处插入值100
intValue.insert(iter,3,200);//通过vector的insert方法将迭代器指向的元素处插入3 //个200的值
cout<<"intValue element:";
for(iter = intValue.begin();iter != intValue.end();iter++) //循环控制输出容器元素值
{
cout<<*iter<<" ";
}
cout<<endl;
//第五部分代码
cout<<"intValue element:"<<endl; //提示下面将会进行一些操作后打印输出容器内容
int size = intValue.size(); //通过vector提供的size()方法获取到该容器内长度
for(int i = 0;i < size;i++) //通过for循环遍历该容器元素
{
iter = intValue.begin(); //首先将迭代器指向容器intValue第一个元素
intValue.erase(iter); //通过vector提供的erase方法删除指向的第一个元素
for(tempIter = intValue.begin();tempIter !=intValue.end();tempIter++)//通过//临时的迭代器访问输出此 //时容器内的元素值
{
cout<<*tempIter<<"";
}
cout<<endl;
}
intValue.clear(); //通过vector提供的clear()方法清空容器intValue内元素
if(intValue.empty()) //通过if结构,结合vector提供的empty()方法判断容器是否为空
{
cout<<"The vector intValue isempty!"<<endl; //为空则输出提示信息
}
else
{
cout<<"haveelements!"<<endl; //不为空则输出提示信息
}
return 0;
}
程序中主要使用了vector容器的插入、删除数据操作。具体程序运行讲解见后面程序剖析。
2.编辑makefile
Linux平台下需要编译的源文件为chapter1601.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1601.o
CC=g++
chapter1601: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1601
clean:
rm-f chapter1601 core $(OBJECTS)
submit:
cp-f -r chapter1601 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序,运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1601.o chapter1601.cpp
g++ chapter1601.o -g -o chapter1601
[developer @localhost src]$ make submit
cp -f -r chapter1601 ../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1601
intValue size:10
intValue element:0 1 2 3 4 5 6 7 8 9
intValue element:6 6 6 6 6
intValue element:200 200 200 100 6 6 6 6 6
intValue element:
200 200 100 6 6 6 6 6
200 100 6 6 6 6 6
100 6 6 6 6 6
6 6 6 6 6
6 6 6 6
6 6 6
6 6
6
The vector intValue is empty!
4.剖析程序
上述实例主要演示了标准模板库vector容器提供的基本操作应用。应用程序中首先定义一个整型参数类型的空向量vector,该向量实例化为处理整型元素的容器。随后定义两个作用于vector相对应的迭代器,迭代器iter、tempIter作用于向量intValue上,类似指针,通常可以用于遍历处理容器中的数据元素。下面将程序分为五个部分来进行剖析讲解。
第一个部分应用实例中使用的第一个方法接口使为push_back(elem)。该方法主要用于向空向量的尾部添加数据元素。程序中采用for循环控制结构,循环地在向量intValue中放入10个元素。其存放的为循环递增的i值。空向量intValue中存放10个元素后,使用该对象调用其方法成员size求取该向量中元素个数,并在屏幕上打印输出。从程序运行结果可以看出,该向量中包含10个数据元素。
第二个部分主要演示向量容器at方法的使用。根据for循环控制结构,递增式访问向量容器中的数据元素。以当前向量长度size返回值为for循环判断值,依次递增变量i。通过传入实参i值调用at方法,返回对应位置的数据元素并打印输出。此时,该容器中存放了刚刚放入的递增值,位置从0~9,共10个元素。
第三个主要演示方法接口assign的使用。根据前面的接口说明,传入两实参分别为5和6。5表示需要替换的元素的个数,6表示相应的值。但是需要注意的是,该替换是整个所有元素的替换,即将当前向量中的元素全部采用5个6来替换,其余元素都不复存在了。随后的at()方法循环遍历打印元素说明了这点。替换后的向量中只剩下了5个元素值为6的数据。
第四个主要演示了insert方法接口(在指定位置插入元素)的使用,首先将迭代器iter指向当前vector的首元素,随后使用当前向量对象调用insert方法,根据迭代器iter所指的位置插入实参100。由于当前迭代器指向位置为向量的首元素,所以在向量中首元素前插入数据100。此时,向量中存放的数据即为(100,6,6,6,6,6)。第二个insert方法接口的调用则采用重载实现的另外一个插入操作接口。该接口主要根据迭代器所指的位置,插入指定数目的指定元素。应用程序中主要在向量的首部插入3个元素为200的数据,此时向量中的数据为(200,200,200,100,6,6,6,6,6)。随后的部分通过for循环控制,通过cout流对象输出代码中采用迭代器遍历向量方法打印输出并验证了该向量中此时的数据元素。
第五个演示了erase方法接口(删除向量中指定位置)的使用。通过两个for循环控制结构,依次递增的删除向量中元素的操作。根据向量中的数据长度首先采用erase方法调用删除向量第一个元素,随后第二重for循环则打印输出剩下的向量数据元素。随后调用了clear方法清空了当前向量,然后根据empty方法成员调用判断,当前向量是否为空,由于前面已经将该向量清空,此时empty方法返回true,随后输出打印对应的提示信息。
vector向量提供了众多的操作方法接口,本书由于篇幅限制无法一一演示使用方法。初学者可以根据上述演示的过程,通过标准库提供的接口基本说明,在应用程序中尝试着使用这些接口。
deque容器为双端可操作队列,非常类似于向量vector数据结构。仅仅是双端队列可以在容器的两端插入以及删除对应的数据元素,并且提供的操作效率较高。双端队列deque同样也提供了随机访问功能,用户也可以根据需要动态地改变队列的大小。
应用程序中要使用双端队列deque容器,同样需要包含相应的头文件(#include<deque>)。同样模板类deque提供了多个构造函数重载实现形式,允许根据需要,定义不同的双端队列的对象实例。下面通过几个实例定义,帮助读者了解deque对象构造情况。
#include <deque> //队列包含的头文件
std::deque; //队列名字空间声明
deque<int> intValue; //定义整型类型队列对象intValue
deque<string>stringValue(100); //定义string标准字符串类型队列对象stringValue
deque<double>doubleValue(10,200.0); //定义double类型队列对象doubleValue
deque<float>floatValue1(floatValue2); //定义float类型队列对象floatValue1
deque<MyString> MyStringValue(first,last); //定义自定义MyString类型队列对象MyStringValue
第一个实例定义中通过整型参数实例化队列对象,定义了双端队列对象实例intValue。此时双端队列为空,可以存储整型类型的数据元素。
第二个实例定义中则采用string字符串类型实例化deque容器。通过在定义时传入实参来指定容器的大小,这里指定该容器大小为100。
第三个实例中使用deque容器构造原型(deque<type> dequename(size,elem))构造双端队列对象实例。其中,size为容器的长度,elem则为所有元素赋初始值。这里,定义了double型双端队列容器doubleValue,容量大小为10,每个元素初始化为200.0。
第四个对象实例构造则是采用内部拷贝构造的方式,将根据现有的deque队列对象实例创建一个新的对象实例。实例中以float类型实例化队列,并以现有的同类型floatValue2对象拷贝构造实现。
最后一个实例定义则以自定义字符串类型实例化deque,定义对象实例以迭代器first到last区间创建有限制范围的双端队列MyStringValue。
deque队列容器与向量容器实现结构类似,甚至在提供的接口方法上也基本相同,仅仅有一小部分的区别。读者可以通过表16.2,了解双端队列deque对外公开提供的操作接口基本情况,以便在应用程序中正确地操作使用。
表格16.2 双端队列deuqe公开方法接口说明
接口方法名称 |
基本功能说明 |
d.assign(n,elem) |
n个elem元素取代当前队列容器中元素 |
d.assign(first,end) |
迭代器first到end区间的元素取代当前队列中元素 |
d.at(n) |
访问当前队列n位置处的元素,并返回该元素 |
d.back() |
返回当前队列尾部元素 |
d.begin() |
返回当前队列第一个元素的迭代器 |
d.clear() |
清空当前队列中所有元素 |
d.empty() |
判断当前队列是否为空,如果为空则返回true |
d.end() |
返回当前队列中最后一个元素的迭代器 |
d.erase(first,end) |
删除当前队列迭代器first到end所指区间的元数据 |
d.erase(iter) |
删除当前队列迭代器iter所指位置元素 |
d.front() |
返回当前队列起始位置元素 |
d.insert(iter,elem) |
当前队列迭代器iter位置处插入元素elem |
d.insert(iter,first,end) |
将迭代器first到end区间的元素插入到当前队列iter所指位置 |
d.insert(iter,num,elem) |
将num个elem元素插入到当前队列iter所指位置处 |
d.max_size() |
返回当前队列容器当前最大容量 |
d.pop_back() |
删除当前队列中最后一个元素 |
d.pop_front() |
删除当前队列中第一个元素 |
d.push_back(elem) |
当前队列的尾部添加元素elem |
d.push_front(elem) |
当前队列的头部添加元素elem |
d.rbegin() |
返回当前队列反向的指向首元素的迭代器 |
d.resize(num,elem) |
将当前队列大小调整为num,并且使用元素elem初始化容器 |
d.size() |
返回当前队列的元素个数 |
d.swap(deque) |
交换当前队列与deque队列的内容 |
下面通过一个完整的双端队列接口操作的实例,帮助读者了解双端队列deque接口使用的基本情况。
1.准备实例
打开UE工具,创建新的空文件并且另存为chapter1602.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1602
* 源文件chapter1602.cpp
* deque容器基本操作实例
*/
#include <iostream>
#include <deque>
using namespace std;
int main()
{
//第一部分代码
deque<char> charValue; //定义char类型队列对象charValue
deque<char> charValue1; //定义char类型队列对象charValue1
deque<char>::iterator iter; //定义char类型队列迭代器iter
deque<char>::iterator tempIter; //定义char类型队列迭代器tempIter
for(int i = 0;i < 10;i++) //for循环从变量i值为0循环10次
{
charValue.push_front(i+65); //通过队列提供push_front方法从队列前面插入元素,值为i+65
charValue1.push_front(i+65); //通过队列提供push_front方法从队列前面插入元素,值为i+65
}
cout<<"charValue elements:"; //打印输出队列中元素值
for(int i = 0;i < charValue.size();i++) //通过for循环,遍历队列长度
{
cout<<charValue.at(i)<<" "; //通过队列的at()方法输出内部元素值
}
cout<<endl;
//第二部分代码
charValue.assign(4,'A'); //通过队列assign方法来替换内部元素,采用4个A替换所有元素
cout<<"charValue elements:";
for(int i = 0;i < charValue.size();i++) //打印输出替换后的队列中元素值
{
cout<<charValue[i]<<" ";
}
cout<<endl;
//第三部分代码
iter = charValue.begin(); //通过begin()方法将迭代器iter指向队列容器charValue首个元素
charValue.insert(iter,'B'); //通过insert()方法将字符B插入iter指向的位置
charValue.insert(iter,4,'C'); //通过insert()方法将4个字符C插入iter指向的位置
cout<<"charValue elements:"; //打印输出插入操作后的队列容器中的元素值
for(iter = charValue.begin();iter != charValue.end();iter++)
{
cout<<*iter<<" ";
}
cout<<endl;
//第四部分代码
cout<<"charValue elements:"<<endl; //提示下面将会通过删除操作pop_back操作容器元素
int size = charValue.size(); //通过队列提供size方法获取队列长度
for(int i = 0;i < size;i++) //循环操作遍历队列元素
{
charValue.pop_back(); //通过队列提供的pop_back方法从尾部删除元素
for(tempIter = charValue.begin();tempIter !=charValue.end();tempIter++)//循环遍历该容器内元素
{
cout<<*tempIter<<"";
}
cout<<endl;
}
//第五部分代码
charValue.swap(charValue1); //通过队列提供的swap方法交换不同的队列
cout<<"charValue elements:";
for(iter = charValue.begin();iter != charValue.end();iter++) //交换后打印输出队列charValue的元素值
{
cout<<*iter<<" ";
}
cout<<endl;
charValue.clear(); //通过队列容器提供的clear方法清空其中的元素
if(charValue.empty()) //通过队列提供的empty判断容器是否为空
{
cout<<"The deque charValue isempty!"<<endl; //为空输出提示
}
else
{
cout<<"haveelements!"<<endl; //不为空输出提示
}
return 0;
}
本实例主函数中演示deque常见操作的使用,如基本的插入、删除数据操作。具体程序运行讲解见后面程序剖析。
2.编辑makefile
Linux平台下需要编译的源文件为chapter1602.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1602.o
CC=g++
chapter1602: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1602
clean:
rm-f chapter1602 core $(OBJECTS)
submit:
cp-f -r chapter1602 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1602.o chapter1602.cpp
g++ chapter1602.o -g -o chapter1602
[developer @localhost src]$ make submit
cp -f -r chapter1602../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1602
charValue elements:J I H G F E D C B A
charValue elements:A A A A
charValue elements:B C C C C A A A A
charValue elements:
B C C C C A A A
B C C C C A A
B C C C C A
B C C C C
B C C C
B C C
B C
B
charValue elements:J I H G F E D C B A
The deque charValue is empty!
4.程序剖析
本实例程序主要演示了deque队列操作,通过该类容器提供的各类方法,实现对容器中各元素操作。主程序中首先定义两个字符类型实例化的空双端队列容器分别为charValue与charValue1,同时定义两个同类型的迭代器iter与tempIter,便于后续操作中使用。下面将会将程序分为五个部分分别剖析讲解。
第一个部分操作实例则是使用push_front方法,在双端队列的头部添加数据元素。此时采用for循环控制结构,两个deque对象都调用相应的push_front方法,把传入的变量i+65作为实参添加元素。由于双端队列中存放着字符型元素,所以此时传入的i+65被内部转化为字符存储。按照应用程序设定,for循环中共把10个元素存放于相应的队列中。随后使用了deque类中at()方法,根据传入的相应元素的位置索引,在for循环中打印输出队列charValue中的元素。由于是从头部开始添加元素,因此最终打印输出的结果为从字符J~A,共10个元素。
第二个部分操作实例中则主要演示了assign方法用于替换双端队列charValue中的元素。根据调用时传入的实参,采用4个'A'字符替换当前队列中的数据元素。随后采用队列方法中下标操作符,根据传入的下标变量遍历打印输出替换后的数据元素,此时双端队列中存放的即为4个字符'A'。
第三个部分实例操作主要演示了双端队列中插入元素,通过deque提供的重载实现的insert方法来实现不同的插入操作功能。首先将预先定义的迭代器iter指向当前队列charValue的首元素,随后调用insert(iter,elem)方法,传入实参为当前队列的首元素迭代器,插入的元素数据为字符'B'。而接下来调用的则是insert方法的重载接口,在指定的位置插入指定个数的元素数据。实例中在队列的首部插入4个字符'C'。随后采用迭代器遍历的方式打印输出双端队列charValue中的元素,此时元素数据即为插入相应数据之后的队列。
第四个部分应用操作实例演示删除元素操作功能,与向量实例中算法思路相同,采用了两个for循环。每次删除一个元素后,都会遍历打印输出队列中所剩下的元素。第一重循环中首先会使用pop_back方法从队列的尾部删除元素,每次删除一个元素,并且随后打印输出整个队列中的元素情况。上述实例的程序运行结果已经很好的体现了这部分的操作应用。
第五个部分应用操作则是演示双端队列中的swap方法,该方法主要用于交换不同的双端队列。当前的队列charValue调用swap方法,该方法传入的实参为另一个队列,此时charValue1队列中仍然存放的元素J~A。该方法最终采用charValue1队列替换charvalue,所以此时采用迭代器遍历输出该队列时,就为J~A的元素。
最后应用实例中当前队列charValue调用了clear方法,清空了该队列中所有元素,随后if判断结构中使用empty方法判断该队列。如果该队列为空,则返回true值,随后打印输出相应提示信息。
STL标准库中list容器实际上是封装实现了双向链表数据结构,该容器非常适合做频繁的插入与删除操作。相对于向量vector来讲,list的优势就在于此,但是list容器采用下标操作速度相对不理想。由于是双向链表结构,list容器提供双向的迭代器用于遍历操作容器中数据,同样支持动态扩充改变容器本身的大小,而不需要额外的操作。
同样应用程序中要使用list容器时,需要包含相应的list的头文件(#include<list>)。链表容器模板类提供了几类构造函数方法接口,下面将会根据提供的list容器构造函数方法讲述其对象构造情况。
#include <list>
list<int> intValue; //定义int整型类型列表对象intValue
list<string>stringValue(10); //定义string标准字符串列表对象stringValue
list<double>doubleValue(10,1.0); //定义double类型列表对象doubleValue
list<int> intValue1(intValue); //定义整型类型列表对象intValue1
list<int> intValue2(firstIter,endIter); //定义整型类型列表对象intValue2
上述实例中一共定义了5个list容器对象实例,分别对应着list容器提供的5个构造函数接口,根据不同的需要,定义相对应的对象实例。
q 第一个对象实例依然是定义一个空整型实例的list容器对象intValue。使用该对象实例时调用构造函数中默认无参数的接口。
q 第二个对象实例定义则使用list提供的带有初始化大小的构造函数list(num)。在构造其对象时,根据传入的实参10,来初始化当前stringValue链表的大小。
q 第三个构造函数使用在具体参数类型实例化list对象时,除了指定list大小以外,同时还指定相应的数据元素来初始化对应的链表中数据。上述实例中定义一个包含10个元素的double型参数链表,同时指定使用1.0数值来初始化对应的元素。
q 第四个实例构造依然采用拷贝构造的方式。定义整型list容器intValue1时,根据传入的实参intValue容器直接拷贝生成该对象。此时,intValue1对象实例的情况与拷贝的list容器对象相同。
q 最后一个构造定义是采用迭代器在构造对象同时指定对应着迭代器范围的元素的链表对象。此时list对象中包含迭代器从firstIter到endIter之间的数据元素。
序列型的容器提供的接口操作大致相同,仅仅在个别操作方面有一些差别。与前面两个容器介绍一样,下面将会通过相应的表格列出list容器大部分操作接口以及操作基本说明,随后通过完整实例来演示其中部分方法,帮助读者了解序列容器基本操作方法的使用情况。表格16.3列出了大部分list容器的接口方法,如下所示。
表格16.3 list容器公开接口方法说明
接口方法名称 |
基本功能说明 |
assign(n,value) |
用n个元素值value替换当前链表中元素 |
assign(firstIter,endIter) |
用迭代器firstIter到endIter区间内的元素替换链表中元素 |
back() |
返回当前链表最后一个元素的引用 |
begin() |
返回指向当前链表首个元素的迭代器 |
clear() |
清空当前链表中所有元素 |
empty() |
判断当前链表中元素是否为空,为空则返回true |
end() |
返回指向当前链表最后一个元素的迭代器 |
erase(iter) |
删除当前链表中指示器iter指向的元素 |
erase(firstIter,endIter) |
删除当前链表迭代器firstIter到endIter区间内的元素 |
front() |
返回当前链表第一个元素的引用 |
insert(iter,value) |
当前链表中迭代器iter所指位置插入元素value |
insert(iter,num,value) |
当前链表中迭代器iter所指位置插入num个元素value |
insert(iter,firstIter,endIter) |
当前链表中迭代器iter所指位置插入区间firstIter到endIter之间的元素 |
max_size() |
返回当前链表最大容量,即当前链表可存放元素最大个数 |
pop_back() |
删除当前链表中最后元素 |
pop_front() |
删除当前链表中首元素 |
push_back(value) |
当前链表尾部添加元素value |
push_front(value) |
当前链表首部添加元素value |
rbegin() |
返回当前链表反向的首元素迭代器 |
remove(value) |
删除当前链表中所有值为value的元素 |
remove_if() |
删除容器指定元素 |
rend() |
放回指向当前反向链表最后一个元素的指示器 |
resize(num,value) |
调整当前链表,使得当前链表为num个元素,并且将元素初始化为value值 |
reverse() |
反调当前链表中元素的顺序 |
size() |
返回当前链表中元素个数 |
sort() |
根据默认排序方式,对当前的链表中元素排序 |
sort(method) |
根据当前给定的模式,对当前链表中元素排序 |
swap(listValue) |
当前链表与listValue链表内部元素互换 |
unique() |
删除当前链表中重复元素 |
链表list容器提供了如上一大堆方法接口,大部分与其它序列容器相仿,调用操作方法大致也相同。下面将会通过一个完整实例演示list容器基本接口方法操作应用,实例代码编辑如下。
1.准备实例
打开UE工具,创建新的空文件并另存为chapter1603.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1603
* 源文件chapter1603.cpp
* list容器基本操作实例
*/
#include <iostream>
#include <list>
using namespace std;
int main()
{
//第一部分代码
list<int> intValue1; //定义int整型类型的list对象intValue1
list<int> intValue2; //定义int整型类型的list对象intValue1
list<int>::iterator iter; //定义整型list的迭代器iter
for(int i = 0;i < 10;i++) //循环控制,整型变量i从值0到10实现10次循环
{
intValue1.push_back(i); //通过list的push_back()方法将i值从尾部放入到list容器中
intValue2.push_front(i); //通过list的push_front()方法将i值从头部放入到list容器中
}
cout<<"List intValue1 elements:"; //提示输出list容器内元素值
for(iter = intValue1.begin();iter != intValue1.end();iter++) //通过for循环遍历list容器元素
{
cout<<*iter<<" "; //输出迭代器指向的list容器里元素的值
}
cout<<endl;
//第二部分代码
iter = intValue1.begin(); //通过begin()方法将容器intValue1首元素赋值给迭代器iter指向
intValue1.insert(iter,3,10); //通过insert()方法将容器intValue1内iter指向的位置插入3个值为10 //的元素
cout<<"List intValue1 elements:"; //提示遍历容器intValue1内的元素
for(iter = intValue1.begin();iter != intValue1.end();iter++) //通过for循环遍历容器intValue1元素
{
cout<<*iter<<" "; //输出迭代器iter指向的元素值
}
cout<<endl;
//第三部分代码
intValue1.remove(10); //通过容器提供的remove()方法删除容器intValue1中值为10的元素
iter = intValue1.begin(); //通过begin()方法将容器intValue1第一个元素赋值给iter指向
intValue1.erase(iter); //通过erase()方法删除iter指向的元素
cout<<"List intValue1 elements:"; //提示输出容器元素
for(iter = intValue1.begin();iter != intValue1.end();iter++) //遍历容器元素
{
cout<<*iter<<" "; //输出迭代器iter指向元素值
}
cout<<endl;
//第四部分代码
intValue1.reverse(); //通过reverse()方法实现容器内元素值反序排列
cout<<"List intValue1 elements:"; //提示输出容器元素
for(iter = intValue1.begin();iter != intValue1.end();iter++) //循环遍历容器元素
{
cout<<*iter<<" "; //输出iter指向值
}
cout<<endl;
intValue1.merge(intValue2); //通过merge()方法合并两个列表容器的元素
cout<<"List intValue1 elements:"; //提述输出容器元素
for(iter = intValue1.begin();iter != intValue1.end();iter++) //循环遍历容器元素
{
cout<<*iter<<" "; //输出iter指向值
}
cout<<endl;
return 0;
}
本实例主要在主函数中实现list常见基本操作使用情况,程序中主要使用了list容器中基本的插入、删除数据操作。具体程序运行讲解见后面程序剖析。
2.编辑makefile
Linux平台下需要编译的源文件为chapter1603.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1603.o
CC=g++
chapter1603: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1603
clean:
rm-f chapter1603 core $(OBJECTS)
submit:
cp-f -r chapter1603 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1603.o chapter1603.cpp
g++ chapter1603.o -g -o chapter1603
[developer @localhost src]$ make submit
cp -f -r chapter1603../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1603
List intValue1 elements:0 1 2 3 4 5 6 7 8 9
List intValue1 elements:10 10 10 0 1 2 3 4 5 67 8 9
List intValue1 elements:1 2 3 4 5 6 7 8 9
List intValue1 elements:9 8 7 6 5 4 3 2 1
List intValue1 elements:9 8 7 6 5 4 3 2 1 9 8 76 5 4 3 2 1 0
4.剖析程序
上述实例主要演了list容器中几个不同于前面的序列容器的方法接口。下面将程序分为四个部分来进行剖析讲解。
第一个部分代码在主程序中首先定义两个空的整型实例化链表容器对象intValue1与intvalue2。随后使用一个for循环控制结构初始化这两个整型list容器的元素。intValue1采用push_back(i)方法循环的从链表尾部添加元素,元素随着i变量的递增而递增。此时打印输出intValue1容器中的元素为“0 1 2 3 4 5 6 7 8 9”。
第二部分代码应用实例中采用insert方法,在当前链表中指定位置插入相应的元素。首先将list容器迭代器指向当前链表intValue1首元素;随后调用insert方法,根据传入的实参在iter迭代器指向的位置插入3个值为10的元素。此时intValue1链表中元素打印输出结果为“10 10 0 1 2 3 4 5 6 7 89”。
第三个部分代码采用remove与erase方法根据传入的实参,删除相应元素。remove方法根据传入的实参数值,删除对应所有元素值与传入的实参值相同的元素。而erase方法则根据实参迭代器指向的位置,删除该迭代器指向的元素。此时打印输出intValue1容器中的内容为“1 2 3 4 5 6 7 8 9”。首先remove(10)删除了当前链表中所有值为10的元素,随后迭代器iter指向当前链表首部元素,将该迭代器作为实参,删除该迭代器指向的元素,即值为0的元素被删除。
第四个部分代码则是反转链表方法,reverse方法用于将当前链表中元素全部按照反顺序排列。反转后的当前链表intValue1的元素为“9 8 7 6 5 4 3 2 1”。最后一个则演示了merge合并链表接口操作,当前链表内容为“9 8 7 6 5 4 3 2 1”,需要合并的链表容器为intValue2,该容器中的元素同样为“9 8 7 6 5 4 3 2 1”,因为之前采用的push_front方法从链表首部添加元素。合并之后的链表则将传入的链表内容放入当前链表的前部,此时intValue1中元素为“9 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1”。
set集合容器是采用二叉树为基础的数据结构实现。由于删除和插入元素操作都只要修改指针的指向,因此set集合在插入与删除元素操作上效率非常高。set是一种允许随机存取元素的容器,同样是键与值关系的容器,但是要求set集合容器中的元素值必须唯一,不能重复。
关联容器set依然是模板类实现。定义对象实例时,根据传入的类型实例化具体的集合。该容器同样提供了几种构造对象的实现方式,用于不同的情况下构造集合对象实例。示例如下。
#include <set>
std::set; //声明set集合名字空间
set<char> charValue1; //定义char字符类型的集合对象charValue1
set<char> charValue2(charValue1); //定义char字符类型的集合对象charValue2
set<char>charValue3(firstIter,endIter); //定义char字符类型的集合对象charValue3
同样,在使用set容器时需要包含其头文件(#include<set>)。另外,STL模板库是封装在std名称空间之下的,所以外部使用时需要外部声明名字空间。上述代码中,根据set容器提供的构造函数,定义三个不同的对象实例。
q 第一个为字符型实例化的空集合set对象实例charValue1,此时该容器实例中无任何数据。
q 第二个则根据set容器提供的拷贝构造函数,将第一个定义的对象实例拷贝生成当前set集合容器的实例对象charValue2。该集合对象实例与实例charValue1完全一样。
q 最后一个则根据当前迭代器firstIter到endIter之间的集合来构造初始化集合对象实例charValue3。此时该对象中包含有上述迭代器区间的集合元素。
关联容器中也提供了大量针对集合容器通用操作接口。与前面介绍的任何一种容器类似,这些方法接口实现结合容器上某种功能。根据需要,开发者可以在实际应用中根据集合容器对象实例来直接调用。set容器大部分方法接口如表16.4所示。
表格16.4 set容器公开接口方法说明
接口方法名称 |
基本功能说明 |
begin() |
返回指向当前集合容器的第一个元素的迭代器 |
clear() |
清空当前集合容器 |
count(value) |
统计并返回当前集合容器中元素value出现的次数 |
empty() |
判断当前集合容器是否为空,为空则返回true |
end() |
返回指向当前集合容器的最后一个元素的迭代器 |
equal_range(value) |
返回当前集合容器中元素为value的第一个位置以及最后一个位置的迭代器 |
erase(iter) |
删除当前集合容器中迭代器iter指向的元素 |
erase(value) |
删除当前集合容器中值为value的元素 |
erase(firstIter,endIter) |
删除当前集合容器中区间为firstIter到endIter迭代器之间的元素 |
find(value) |
返回当前集合容器中指向元素value的迭代器,如果没有找到则返回该集合最后一个元素的迭代器与end方法同 |
insert(value) |
当前集合容器中插入元素value,按照默认方式排序元素 |
insert(iter,value) |
当前集合容器中iter迭代器指向位置前插入元素value,并且返回一个指向该元素的迭代器 |
insert(firstIter,endIter) |
将迭代器firstIter到endIter区间的元素插入到当前集合容器中 |
lower_bound(value) |
如果value元素在当前集合中则返回当前元素指向的迭代器,如果value元素不在集合中则返回指向下一个元素的迭代器 |
upper_bound(value) |
如果value元素在当前集合中则返回下一个元素指向的迭代器,如果不存在也返回下一个元素指向的迭代器 |
max_size() |
返回当前集合容器的最大容量 |
rebegin() |
返回当前反向集合容器中第一个元素的迭代器 |
rend() |
返回当前反向集合容器中最后一个元素的迭代器 |
size() |
返回当前集合中实际元素个数 |
swap(setcontains) |
交换两个集合容器内容 |
set集合容器操作接口大部分与序列容器相同,下面将会通过完整操作set集合容器的实例,演示提供的不同的方法接口的应用情况,实例代码编辑如下所示。
1.准备实例
打开UE工具,创建新的空文件并且另存为chapter1604.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1604
* 源文件chapter1604.cpp
* set基本操作实例
*/
#include <iostream>
#include <set>
using namespace std;
int main()
{
//第一部分代码
set<char> charValue; //定义字符类型集合对象charValue
set<char>::iterator iter; //定义字符类型集合迭代器iter
for(int i = 0;i < 10;i++) //for循环从变量i为0开始循环10次
{
charValue.insert(65+i); //通过集合的insert方法向集合插入元素,元素值为65+i,其中i为变量
}
cout<<"set elements:"; //提述循环遍历容器中的元素
for(iter = charValue.begin();iter != charValue.end();iter++) //通过for循环,通过迭代器遍历容器charValue
{
cout<<*iter<<" "; //打印迭代器指向元素的值
}
cout<<endl;
//第二部分代码
iter = charValue.begin(); //通过begin()方法迭代器iter指向容器charValue的首元素
charValue.erase(++iter); //通过erase()方法删除迭代器指向的下一个元素的值
cout<<"set elements:"; //打印输出此时的集合内容
for(iter = charValue.begin();iter != charValue.end();iter++) //同样采用迭代器遍历容器charValue
{
cout<<*iter<<" "; //输出迭代器指向的元素值
}
cout<<endl;
//第三部分代码
int count; //定义整型变量count
count = charValue.count('B'); //通过集合的count方法计算容器中元素为B字符的个数赋值给count变量
cout<<"B counts:"<<count<<endl; //打印输出其中指定字符B的元素个数
//第四部分代码
iter = charValue.find('B'); //通过find()方法找出元素B的位置,将结果赋值给迭代器iter
if(iter == charValue.end()) //如果遍历值容器尾部还未找到该元素B,则打印提示信息
{
cout<<"not found thiselement!"<<endl;
}
else
cout<<"found thiselement:"<<*iter<<endl; //否则提示找到
//第五部分代码
iter = charValue.lower_bound('E'); //通过lower_bound()方法返回元素E指定的位置,赋值给迭代器iter
cout<<"current*iter:"<<*iter<<endl; //输出迭代器指向的元素值
charValue.clear(); //通过clear()方法清空容器charValue
if(charValue.empty()) //通过empty()方法判断容器是否为空
{
cout<<"set contains isempty!"<<endl; //为空输出提示信息
}
else
cout<<"not empty!"<<endl; //不为空,输出提示信息
return 0;
}
本实例主要在主函数中实现set常见基本操作使用情况,程序中主要使用了set容器中基本的插入、删除数据操作。具体程序运行讲解见后面程序剖析
2.编辑makefile
Linux平台下需要编译的源文件为chapter1604.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1604.o
CC=g++
chapter1604: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1604
clean:
rm-f chapter1604 core $(OBJECTS)
submit:
cp-f -r chapter1604 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1604.o chapter1604.cpp
g++ chapter1604.o -g -o chapter1604
[developer @localhost src]$ make submit
cp -f -r chapter1604../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1604
set elements:A B C D E F G H I J
set elements:A C D E F G H I J
B counts:0
not found this element!
current *iter:E
set contains is empty!
4.程序剖析
上述实例中主要演示了部分set集合容器的方法接口操作。
第一个部分定义字符型实例化的set集合空容器charValue,同时定义该类型容器的迭代器iter。set容器并没有提供类似序列容器的push操作,容器对象创建后,根据for循环控制结构采用insert方法循环插入10个元素。该元素值为65+i内部转化为相应的字符。set集合容器根据插入的元素会按照默认的方式来排序当前的数据元素,本实例中是按照ASCII码值从小到大插入数据的。默认情况下,即使不是按照这个顺序插入数据,内部也会采用默认的方式来排序容器中的元素。
set集合容器对象创建后,通过迭代器遍历该容器,并打印输出其中的元素。10个元素从A开始根据i变量的递增分别插入元素为A~J字符。
第二部分代码操作演示通过erase方法删除集合容器中迭代器指定位置的元素。首先使迭代器iter定位指向容器的首部位置,调用erase方法内部iter优先执行了++操作运算,将迭代器指向下一个元素,所以此时删除集合中第二个元素,即元素'B'。通过迭代器遍历方式打印输出对应的集合,其中为'B'的元素已被删除。
第三部分代码操作接口演示通过count方法接口统计当前集合容器中指定元素的个数。首先定义计数变量count存储统计的结果。当前集合对象实例调用count方法统计字符'B'的个数,将其值赋给count变量,最后打印输出count计数结果。由于统计的字符'B'在集合中不存在,所以统计结果为0。
第四部分代码接口实例中演示find方法来查找集合中对应的元素。调用find方法指定需要查找的元素为'B'字符,并将结果赋给迭代器iter,随后开始判断该迭代器是否指向end方法返回的迭代器指向元素。一旦判断为真,则表明没有找到当前字符'B',内部迭代器指向了集合中end方法返回指向的位置。由于元素'B'不存在,则该判断成立。随后打印输出相应的没有找到元素的提示信息。
第五部分代码接口实例操作演示了lower_bound方法。根据传入的元素返回指向元素迭代器,将该迭代器指向赋给iter,最后为了演示该迭代器变化的结果则打印输出其迭代器指向的元素,以示验证。由于传入的元素为'E'存在于集合中,则返回当前元素的迭代器,最后打印输出结果依然为元素'E'。
最后调用clear方法清空当前集合容器charValue中所有元素,随后调用其empty方法根据返回的结果打印输出对应的提示信息。
关联容器中set容器适合单个元素值的存取,而map容器则提供了键/值对的存储。map容器有时被称为关联数组。map中的元素提供了键值对操作,键对应用着索引时使用的标号,值对应着键存储的数据,是可供被检索查找的具体数据值。map与set容器相同,其中元素都是以有序的方式存储的。因此,map容器支持高效率的检索与存储操作,通常寻求高效存储检索需求时可以使用map容器。
map容器同样提供了多个不同的构造函数实现,根据实际需要可以定义实现不同的对象实例。下面介绍使用map容器中提供的多个构造函数定义相应的对象实例。实现代码如下。
#include <map>
std::map;
map<int,string> testMap1;
map<int,string> testMap2(testMap1);
map<int,string>testMap3(firstIter,endIter);
与前面介绍的容器基本类似,map提供的构造函数接口基本也是这几种,不同的是参数实例化时需要至少指定两个类型,一个为map中的键类型,另一个则为键对应的数据类型。
q 第一个实例testMap1,参数实例中int型表示其键的类型,string表示键对应的数据类型,该map对象实例为空。
q 第二个构造对象实例则是采用拷贝构造函数。通过已经定义的map对象实例testMap1,拷贝构造成新的对象testMap2。该对象实例中拥有与testMap1同样的内容。
q 第三个map对象实例中同样的参数实例化,只是采用迭代器firstIter与endIter区间的元素初始化该对象testMap3。
表16.5列出基本的map容器提供的接口操作。
表格16.5 map容器公开接口方法说明
接口方法名称 |
基本功能说明 |
begin() |
放回当前map容器第一个元素指向的迭代器 |
count(value) |
返回当前map容器中元素value的次数 |
equal_range(value) |
返回当前map容器中value元素第一次出现与最后一次出现的两个迭代器 |
erase(value) |
删除map容器中映射为value的元素 |
erase(iter) |
删除map容器中迭代器iter指向的元素 |
erase(firstIter,endIter) |
删除map容器中迭代器firstIter到endIter区间的映射元素 |
clear() |
清空当前map容器中所有元素 |
empty() |
判断当前map容器是否为空,如果为空则返回true |
end() |
返回当前map容器最后一个映射元素的迭代器 |
find(value) |
返回当前map容器中指向元素value的迭代器,如果查找不到则返回方法end()方法所指向的迭代器 |
insert(iter,pair) |
当前map容器中iter指向的位置插入键值对pair,并且返回指向该键值对的迭代器 |
insert(firstIter,endIter) |
当前map容器中插入迭代器firstIter到endIter区间的元素 |
insert(pair) |
当前map容器中插入相应的pair对元素 |
lower_bound(value) |
如果value元素在当前集合中则返回当前元素指向的迭代器,如果value元素不在集合中则返回指向下一个元素的迭代器 |
upper_bound(value) |
如果value元素在当前集合中则返回下一个元素指向的迭代器,如果不存在也返回下一个元素指向的迭代器 |
max_size() |
返回当前map容器中最大的容量 |
rbegin() |
返回当前map容器反向的指向第一个元素的迭代器 |
rend() |
返回当前map容器反向的指向最后一个元素的迭代器 |
size() |
返回当前map容器中实际元素的数量 |
swap(testMap) |
交换当前map容器与testMap容器内容 |
key_comp() |
返回当前map容器的类型为key_compare的对象,该类型用于map容器中键的排序 |
value_comp() |
返回当前map容器类型为value_compare的对象,该类型用于map容器中值得排序 |
map容器提供的接口方法操作与set容器类似,只是map中接口总是操作着键/值对。下面通过一个完整实例简单演示map容器中几个方法接口的实际应用情况。
1.准备实例
打开UE工具,创建新的空文件并且另存为chapter1605.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示。
/**
* 实例chapter1605
* 源文件chapter1605.cpp
* map容器基本操作实例
*/
#include <iostream>
#include <map>
using namespace std;
int main()
{
//第一部分代码
map<int,char> testMap; //定义整型和字符型键值对的map对象testMap
map<int,char>::iterator iter; //定义同类型的迭代器iter
for(int i = 0;i < 5;i++) //循环控制结构,通过i变量值从0到5循环5次
{
testMap.insert(map<int,char>::value_type(i,65+i)); //通过insert()方法插入元素
}
cout<<"map elements:"<<endl; //提示打印map容器信息
for(iter = testMap.begin();iter != testMap.end();iter++) //通过循环控制遍历容器testMap
{
cout<<iter->first<<""<<iter->second<<endl; //输出testMap容器键值对值
}
//第二部分代码
testMap.insert(map<int,char>::value_type(8,65+4)); //通过insert方法在键为8位置插入值65+4
testMap.insert(map<int,char>::value_type(7,65+4)); //通过insert方法在键为7位置插入值65+4
testMap[6] = 65+4; //通过下标方式将65+4值放入键为6的位置
cout<<"map elements:"<<endl; //提示输出map容器内容
for(iter = testMap.begin();iter != testMap.end();iter++) //通过循环控制遍历容器testMap
{
cout<<iter->first<<""<<iter->second<<endl; //输出testMap容器键值对值
}
//第三部分代码
iter = testMap.begin(); //通过begin()方法将map的首元素赋值iter指向
testMap.erase(iter); //通过erase()方法删除iter指定的容器内元素值
testMap.erase(++iter); //通过erase()方法删除iter指定的下一个容器内元素值
cout<<"map elements:"<<endl; //提示打印map容器信息
for(iter = testMap.begin();iter != testMap.end();iter++) //通过循环控制遍历容器testMap
{
cout<<iter->first<<""<<iter->second<<endl; //输出testMap容器键值对值
}
//第四部分代码
testMap.clear(); //通过clear()方法清空map容器
if(testMap.empty()) //通过empty()方法判断容器是否为空
{
cout<<"The Map testMap isempty!"<<endl; //为空输出提示信息
}
else
cout<<"haveelements!"<<endl; //不为空输出提示信息
return 0;
}
本实例主要在主函数中实现map常见基本操作使用情况,程序中主要使用了map容器中基本的插入、删除数据操作。具体程序运行讲解见后面程序剖析。
2.编辑makefile
Linux平台下需要编译的源文件为chapter1605.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1605.o
CC=g++
chapter1605: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1605
clean:
rm-f chapter1605 core $(OBJECTS)
submit:
cp-f -r chapter1605 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1605.o chapter1605.cpp
g++ chapter1605.o -g -o chapter1605
[developer @localhost src]$ make submit
cp -f -r chapter1605../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1605
map elements:
0 A
1 B
2 C
3 D
4 E
map elements:
0 A
1 B
2 C
3 D
4 E
6 E
7 E
8 E
map elements:
2 C
3 D
4 E
6 E
7 E
8 E
The Map testMap is empty!
4.程序剖析
本实例主要演示容器map的各类操作使用方法,下面将会分为X个部分来剖析讲解实例代码。
第一部分代码实例中首先定义空的map容器对象testMap,该容器键的类型为int型,而对应的数据值则为字符型,另外定义该map容器对象的迭代器iter。通过for循环控制结构采用insert方法根据变量i向map容器中插入键值对的元素。其中,键为递增的i变量,65+i转换为字符为键对应的数据值。随后通过迭代器iter遍历当前map容器,打印testMap中的键值对。其中,迭代器下first表示键的内容,而iter下的second表示键对应的数据。
第二部分代码示例主要演示map容器中插入元素的方法,主要采用两种方式:一种为insert方法,而另一种则为采用下标操作符的方式。实例代码中首先采用insert方法分别在位置键为8和7处插入相应的数据(65+4转换的字符)。随后,采用重载实现的下标操作符,下标操作符中键为6,对应的数据值直接赋值即可。插入操作作完后,通过迭代器遍历容器testMap打印输出验证插入元素。此时对应的6、7、8键上添加了元素字符'E'。
第三部分代码实例演示map容器中删除元素的操作。首先将迭代器iter定位到testMap首位置,随后调用erase方法,删除iter指向的元素。随后,同样调用erase方法,优先执行++运算将iter定位到第二个位置,删除掉对应位置的元素。此时根据迭代器iter遍历打印输出testMap容器中的键值对,元素中少了键为0、1的键值对。
第四部分代码最后调用clear方法清空testMap容器中的所有元素。随后,通过empty方法判断当前容器是否为空,如果为空则返回true,打印输出对应的提示信息。
STL关联容器容器set与map提供存放数据元素,set中要求存放的数据元素与键值可以是同一个,另外存入的数据元素不能重复。而map容器存储键值对时,一个特定的键只能与一个元素相互关联。针对以上限制,STL库提供了multiset与multimap容器操作。multiset容器则允许集合中存在同样重复的元素,而multimap容器允许重复的键值对存在,键可以重复,键对应的关联数据也可以是多种重复的。下面通过一个完整实例,演示multiset与multimap容器区别于set与map的特性,实例代码如下。
1.准备实例
打开UE工具,创建新的空文件并且另存为chapter1606.cpp。该代码文件随后会同makefile文件一起通过FTP工具传输至Linux服务器端,客户端通过scrt工具访问操作。程序代码文件编辑如下所示
/**
* 实例chapter1606
* 源文件chapter1606.cpp
* multiset、multimap容器基本操作实例
*/
#include <iostream>
#include <map>
#include <set>
using namespace std;
int main()
{
//第一部分代码
multiset<int> testSet; //定义整型类型集合容器testSet
multimap<int,char> testMap; //定义整型和字符型键值对的map容器testMap
multiset<int>::iterator iter1; //定义集合容器迭代器iter1
multimap<int,char>::iterator iter2; //定义map容器迭代器iter2
for(int i = 0;i < 5;i++) //循环结构控制,变量i从0到值5,循环5次
{
testSet.insert(i); //通过insert()方法插入元素i进入集合testSet容器
testMap.insert(multimap<int,char>::value_type(i,65+i)); //通过insert()向testMap容器插入元素值
}
cout<<"mulitiset elements:"; //提示打印输出容器mulitiset元素
for(iter1 = testSet.begin();iter1 != testSet.end();iter1++) //通过for循环遍历容器元素
{
cout<<*iter1<<" "; //输出迭代器指向元素值
}
cout<<endl;
//第二部分代码
cout<<"mulitimap elements:"<<endl; //提示打印输出容器mulitimap元素
for(iter2 = testMap.begin();iter2 != testMap.end();iter2++) //通过for循环遍历容器元素
{
cout<<iter2->first<<""<<iter2->second<<endl; //输出迭代器指向的元素值
}
iter1 = testSet.begin(); //通过begin()方法获取容器testSet的首元素位置赋值给iter1指向
testSet.insert(iter1,1); //通过insert()方法在iter1指定位置处插入元素值1
cout<<"mulitiset elements:"; //提示打印输出容器testSet元素
for(iter1 = testSet.begin();iter1 != testSet.end();iter1++) //通过for循环遍历容器元素
{
cout<<*iter1<<" "; //输出迭代器指向的元素值
}
cout<<endl;
testMap.insert(multimap<int,char>::value_type(1,65+3)); //通过insert()方法向容器testMap中插入元素值
cout<<"mulitimap elements:"<<endl; //提示打印输出容器元素内容
for(iter2 = testMap.begin();iter2 != testMap.end();iter2++) //通过for循环遍历容器元素
{
cout<<iter2->first<<""<<iter2->second<<endl; //输出迭代器指向的元素值
}
testSet.clear(); //通过clear()方法清空容器testSet
testMap.clear(); //通过clear()方法清空容器testMap
return 0;
}
本实例主要在主函数中实现multiset、multimap常见基本操作使用情况,程序中主要使用了multiset、multimap容器中基本的插入、删除数据操作,体现了与map、set等容器操作的基本区别。具体程序运行讲解见后面程序剖析。
2.编辑makefile
Linux平台下需要编译的源文件为chapter1606.cpp,相关makefile工程文件编译命令编辑如下所示。
OBJECTS=chapter1606.o
CC=g++
chapter1606: $(OBJECTS)
$(CC)$(OBJECTS) -g -o chapter1606
clean:
rm-f chapter1606 core $(OBJECTS)
submit:
cp-f -r chapter1606 ../bin
3.编译运行程序
当前shell下执行make命令,生成可执行程序文件,随后通过make submit命令提交程序文件至本实例bin目录,通过cd命令定位至bin目录,执行该程序文件运行结果如下所示。
[developer@localhost src]$ make
g++ -c-o chapter1606.o chapter1606.cpp
g++ chapter1606.o -g -o chapter1606
[developer @localhost src]$ make submit
cp -f -r chapter1606../bin
[developer @localhost src]$ cd ../bin
[developer @localhost bin]$ ./chapter1606
mulitiset elements:01 2 3 4
mulitimap elements:
0 A
1 B
2 C
3 D
4 E
mulitiset elements:01 1 2 3 4
mulitimap elements:
0 A
1 B
1 D
2 C
3 D
4 E
4.程序剖析
上述实例程序中演示了使用multiset与multimap容器存放重复数据元素的情况。下面将会将代码分为两个部分进行剖析讲解。
第一个部分代码首先定义了容器multiset与multimap对象实例。其中,multiset容器采用int型参数实例化对象为testSet;而multimap容器则采用键为int型,而对应的数据为char型的对象实例testMap。另外定义了基于上述两个容器之上的迭代器iter1与iter2。
之后通过for循环控制结构,分别向两个容器中插入5个元素。multiset容器对象testSet中循环存放着从0~1的不重复元素,而multimap容器对象testMap中循环存放着键为0~5,对应的数据元素为A~E的元素。插入操作完成后,通过各自的迭代器遍历访问其中的元素并打印输出各自的元素。
第二个部分代码随后将multiset容器的迭代器iter1指向该实例testSet容器对象的首位元素。调用insert方法在该位置插入值为1的元素,并且通过迭代器遍历访问并打印输出结果。该结果中此时允许存在重复的值为1的元素。而针对multimap容器,则使用testMap对象调用insert方法插入键为1对应的数据元素为'D'。此时,通过迭代器iter2遍历打印。输出结果中除了键可以重复以外,相应的数据元素也可以重复。
与set、map容器相比,multiset与multimap容器可以满足特殊需求情况下的应用。尤其是当所要处理的数据允许重复以及需要快速地存储与检索时,可以考虑使用multiset与multimap容器。
来自为知笔记(Wiz)