STL容器 vector ,set, map, multimap
1.1 什么是STL?
STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
STL的一个重要特点是数据结构和算法的分离。尽管这是个简单的概念,但这种分离确实使得STL变得非常通用。例如,由于STL的sort()函数是完全通用的,你可以用它来操作几乎任何数据集合,包括链表,容器和数组;
STL另一个重要特性是它不是面向对象的。为了具有足够通用性,STL主要依赖于模板而不是封装,继承和虚函数(多态性)——OOP的三个要素。你在STL中找不到任何明显的类继承关系。这好像是一种倒退,但这正好是使得STL的组件具有广泛通用性的底层特征。另外,由于STL是基于模板,内联函数的使用使得生成的代码短小高效;
从逻辑层次来看,在STL中体现了泛型化程序设计的思想,引入了诸多新的名词,比如像需求(requirements),概念(concept),模型(model),容器(container),算法(algorithmn),迭代子(iterator)等。与OOP(object-oriented programming)中的多态(polymorphism)一样,泛型也是一种软件的复用技术;从实现层次看,整个STL是以一种类型参数化的方式实现的,这种方式基于一个在早先C++标准中没有出现的语言特性--模板(template)。
1.2 STL内容介绍
STL中六大组件:
1)容器(Container),是一种数据结构,如list,vector,和deques ,以模板类的方法提供。为了访问容器中的数据,可以使用由容器类输出的迭代器;
2)迭代器(Iterator),提供了访问容器中对象的方法。例如,可以使用一对迭代器指定list或vector中的一定范围的对象。迭代器就如同一个指针。事实上,C++的指针也是一种迭代器。但是,迭代器也可以是那些定义了operator*()以及其他类似于指针的操作符地方法的类对象;
3)算法(Algorithm),是用来操作容器中的数据的模板函数。例如,STL用sort()来对一个vector中的数据进行排序,用find()来搜索一个list中的对象,函数本身与他们操作的数据的结构和类型无关,因此他们可以在从简单数组到高度复杂容器的任何数据结构上使用;
4)仿函数(Function object)
5)迭代适配器(Adaptor)
6)空间配制器(allocator)
下面我将依次介绍STL的这三个主要组件。
1.2.1 容器
STL中的容器有队列容器和关联容器,容器适配器(congtainer adapters:stack,queue,priority queue),位集(bit_set),串包(string_package)等等。
(1)序列式容器(Sequence containers),每个元素都有固定位置--取决于插入时机和地点,和元素值无关,vector、deque、list;
Vectors:将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时;
Deques:是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速。但是在中部或头部安插元素比较费时;
Lists:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针;
(2)关联式容器(Associated containers),元素位置取决于特定的排序准则,和插入顺序无关,set、multiset、map、multimap;
Sets/Multisets:内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,Multisets内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
Maps/Multimaps:Map的元素是成对的键值/实值,内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素,内部由二叉树实现,便于查找;
set 和multiset ,两者用法相像,前者不允许插入重复值,后者可以插入重复值
map和multimap ,两者用法相像,前者不允许插入重复值,后者可以插入重复值
C++ MultiSets
多元集合(Multi
C++ MultiMaps
C++ Multimaps和maps很相似,但是MultiMaps允许重复的元素。
begin() | 返回指向第一个元素的迭代器 |
clear() | 删除所有元素 |
count() | 返回一个元素出现的次数 |
empty() | 如果multimap为空则返回真 |
end() | 返回一个指向multimap末尾的迭代器 |
equal_range() | 返回指向元素的key为指定值的迭代器对 |
erase() | 删除元素 |
find() | 查找元素 |
get_allocator() | 返回multimap的配置器 |
insert() | 插入元素 |
key_comp() | 返回比较key的函数 |
lower_bound() | 返回键值>=给定元素的第一个位置 |
max_size() | 返回可以容纳的最大元素个数 |
rbegin() | 返回一个指向mulitmap尾部的逆向迭代器 |
rend() | 返回一个指向multimap头部的逆向迭代器 |
size() | 返回multimap中元素的个数 |
swap() | 交换两个multimaps |
upper_bound() | 返回键值>给定元素的第一个位置 |
value_comp() | 返回比较元素value的函数 |
Sets)和集合(Sets)相像,只不过支持重复对象。
返回指向第一个元素的迭代器 |
|
清除所有元素 |
|
返回指向某个值元素的个数 |
|
如果集合为空,返回true |
|
返回指向最后一个元素的迭代器 |
|
返回集合中与给定值相等的上下限的两个迭代器 |
|
删除集合中的元素 |
|
返回一个指向被查找到元素的迭代器 |
|
返回多元集合的分配器 |
|
在集合中插入元素 |
|
返回一个用于元素间值比较的函数 |
|
返回指向大于(或等于)某值的第一个元素的迭代器 |
|
返回集合能容纳的元素的最大限值 |
|
返回指向多元集合中最后一个元素的反向迭代器 |
|
返回指向多元集合中第一个元素的反向迭代器 |
|
多元集合中元素的数目 |
|
交换两个多元集合变量 |
|
返回一个大于某个值元素的迭代器 |
|
返回一个用于比较元素间的值的函数 |
容器类自动申请和释放内存,无需new和delete操作。vector基于模板实现,需包含头文件vector。
//1.定义和初始化
vector<int> vec1; //默认初始化,vec1为空
vector<int> vec2(vec1); //使用vec1初始化vec2
vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
vector<int> vec4(10); //10个值为的元素
vector<int> vec5(10,4); //10个值为的元素
//2.常用操作方法
vec1.push_back(100); //添加元素
int size = vec1.size(); //元素个数
bool isEmpty = vec1.empty(); //判断是否为空
cout<<vec1[0]<<endl; //取得第一个元素
vec1.insert(vec1.end(),5,3); //从vec1.back位置插入个值为的元素
vec1.pop_back(); //删除末尾元素
vec1.erase(vec1.begin(),vec1.end());//删除之间的元素,其他元素前移
cout<<(vec1==vec2)?true:false; //判断是否相等==、!=、>=、<=...
vector<int>::iterator iter = vec1.begin(); //获取迭代器首地址
vec1.clear(); //清空元素
//3.遍历
//下标法
int length = vec1.size();
for(int i=0;i<length;i++)
{
cout<<vec1[i];
}
cout<<endl<<endl;
//迭代器法
vector<int>::const_iterator iterator = vec1.begin();
for(;iterator != vec1.end();iterator++)
{
cout<<*iterator;
}
1.2.2.STL迭代器
Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。
迭代器的作用:能够让迭代器与算法不干扰的相互发展,最后又能无间隙的粘合起来,重载了*,++,==,!=,=运算符。用以操作复杂的数据结构,容器提供迭代器,算法使用迭代器;常见的一些迭代器类型:iterator、const_iterator、reverse_iterator和const_reverse_iterator,实例如下:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(3); //数组尾部插入3
v.push_back(2);
v.push_back(1);
v.push_back(0);
cout << " 下标 " << v[3] << endl;
cout << " 迭代器 " << endl;
for(vector<int>::iterator i = v.begin();i!= v.end();++i)
{
cout << *i << " ";
}
cout << endl;
//在第一个元素之前插入111 insert begin+n是在第n个元素之前插入
v.insert(v.begin(),111);
//在最后一个元素之后插入222 insert end + n 是在n个元素之后插入
v.insert(v.end(),222);
for(vector<int>::iterator i = v.begin();i!= v.end();++i)
{
cout << *i << " ";
}
cout << endl;
vector<int> arr(10);
for(int i = 0; i < 10; i++)
{
arr[i] = i;
}
for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
{
cout << *i << " ";
}
cout << endl;
//删除 同insert
arr.erase(arr.begin());
for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
{
cout << *i << " " ;
}
cout << endl ;
arr.erase(arr.begin(),arr.begin()+5);
for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
{
cout << *i << " " ;
}
cout << endl ;
return 0 ;
}
- 运用value_type
为避免隐式型别转换,利用value_type明白传递正确型别,value_type是容器本身提供的型别定义。
std::map<std::string,float> coll;
'''
coll.insert(std::map<std::string,float>::value_type("otto",22.3));
- 运用pair<>
std::map<std::string,float> coll;
'''
// use implicit conversion:
coll.insert(std::pair<std::string,float>("otto",22.3));
// use no implicit conversion
coll.insert(std::pair<const std::string,float>("otto",22.3));
-
运用make_pair<>
会根据传入的参数构造出一个pair对象。
std::map<std::string,float> coll;
'''
coll.insert(std::make_pair("otto",22.3));
三、程序示例
//example of map
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
typedef map<string, float> StringFloatMap;
StringFloatMap stocks;
stocks["BASF"] = 369.50;
stocks["VW"] = 413.50;
stocks["Daimler"] = 815.00;
stocks["BMW"] = 834.00;
stocks["Siemens"] = 842.20;
StringFloatMap::iterator pos;
for (pos = stocks.begin(); pos != stocks.end(); ++pos){
cout << "stock: " << pos->first << "\t"
<< "price: " << pos->second << endl;
}
cout << endl;
for (pos = stocks.begin(); pos != stocks.end(); ++pos){
pos->second *= 2;
}
for (pos = stocks.begin(); pos != stocks.end(); ++pos){
cout << "stock: " << pos->first << "\t"
<< "price: " << pos->second << endl;
}
cout << endl;
stocks["Volkswagen"] = stocks["VW"];
stocks.erase("VW");
for (pos = stocks.begin(); pos != stocks.end(); ++pos){
cout << "stock: " << pos->first << "\t"
<< "price: " << pos->second << endl;
}
cout << endl;
stocks["Volk"];
for (pos = stocks.begin(); pos != stocks.end(); ++pos){
cout << "stock: " << pos->first << "\t"
<< "price: " << pos->second << endl;
}
return 0;
}
//example of multimap
#include <iostream>
#include <map>
#include <string>
#include <iomanip>
using namespace std;
int main()
{
typedef multimap<string, string> StrStrMMap;
StrStrMMap dict;
dict.insert(StrStrMMap::value_type("day", "Tag"));
dict.insert(StrStrMMap::value_type("strange", "fremd"));
dict.insert(StrStrMMap::value_type("car", "Auto"));
dict.insert(pair<string,string>("smart", "elegant"));
dict.insert(pair<string, string>("trait", "Merkmal"));
dict.insert(pair<string, string>("strange", "seltsam"));
dict.insert(make_pair("smart", "raffiniert"));
dict.insert(make_pair("smart", "klug"));
dict.insert(make_pair("clever", "raffiniert"));
StrStrMMap::iterator pos;
cout.setf(ios::left, ios::adjustfield);
cout << ' ' << setw(10) << "english"
<< "german" << endl;
cout << setfill('-') << setw(20) << " "
<< setfill('-') << endl;
for (pos = dict.begin(); pos != dict.end(); ++pos){
cout << ' ' << setw(10) << pos->first.c_str()
<< pos->second << endl;
}
cout << endl;
string word = "smart";
cout << word << ": " << endl;
for (pos = dict.lower_bound(word); pos != dict.upper_bound(word); ++pos){
cout << " " << pos->second << endl;
}
word = "raffiniert";
cout << word << ": " << endl;
for (pos = dict.begin(); pos != dict.end(); ++pos){
if (pos->second == word){
cout << " " << pos->first << endl;
}
}
cout << endl;
dict.erase("car");
for (pos = dict.begin(); pos != dict.end();) {
if (pos->second == "klug") {
dict.erase(pos++);
}
else {
++pos;
}
}
cout.setf(ios::left, ios::adjustfield);
cout << ' ' << setw(10) << "english"
<< "german" << endl;
cout << setfill('-') << setw(20) << " "
<< setfill('-') << endl;
for (pos = dict.begin(); pos != dict.end(); ++pos){
cout << ' ' << setw(10) << pos->first.c_str()
<< pos->second << endl;
}
cout << endl;
return 0;
}
输出结果:
上一篇: C++ 基础篇
推荐阅读
-
set容器与map容器的简单应用
-
荐 JAVA13——容器(Map接口、Equals和hashcode、Set接口、容器存储数据练习、Iterator接口)
-
C++STL之set容器
-
详解C++ STL vector容器访问元素的几种方式
-
java 容器集合类的区别用法(Vector ArrayList Map)
-
list、vector、map容器erase的区别
-
Java的collection集合/set容器/list容器/map容器
-
stl中的map、set、multimap、multiset,兼谈OceanBase造*
-
set容器与map容器的简单应用
-
(C++)错误的map删除操作和STL中容器的迭代器的底层实现机制