C++中STL使用
来源:互联网 发布:网络性能管理系统 编辑:程序博客网 时间:2024/06/16 17:47
1.1概述
STL = Standard Template Library,标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map等,STL也是算法和其他一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。STL的目的是标准化组件,这样就不用重新开发,可以使用现成的组件。STL现在是C++的一部分。
在C++标准中,STL被组织为下面的17个头文件:<algorithm>(算法)、<deque>(双队列)、<functional>(功能)、<iterator>(迭代器)、<array>(数组)、<vector>(矢量)、<list>(链表)、<forward_list>、<map>(映射)、<unordered_map>(无序)、<memory>(记忆)、<numeric>(数字)、<queue>(列队)、<set>(集合)、<unordered_set>(无序)、<stack>(堆)和<utility>(实用)。
1.2组成部分
STL可分为容器(containers)、迭代器(iterators)、空间配置器(allocator)、配接器(adapters)、算法(algorithms)、仿函数(functors)六个部分。
1.2.1容器
在实际的开发过程中,数据结构本身的重要性不会逊于操作于数据结构的算法的重要性,当程序中存在着对时间要求很高的部分时,数据结构的选择就显得更加重要。
经典的数据结构数量有限,但是我们常常重复着一些为了实现向量、链表等结构而编写的代码,这些代码都十分相似,只是为了适应不同数据的变化而在细节上有所出入。STL容器就为我们提供了这样的方便,它允许我们重复利用已有的实现构造自己的特定类型下的数据结构,通过设置一些模板类,STL容器对最常用的数据结构提供了支持,这些模板的参数允许我们指定容器中元素的数据类型,可以将我们许多重复而乏味的工作简化。
容器部分主要由头文件<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>组成。对于常用的一些容器和容器适配器(可以看作由其它容器实现的容器),可以通过下表总结一下它们和相应头文件的对应关系。
序列式容器
向量(vector) 连续存储的元素<vector>;
列表(list) 由节点组成的双向链表,每个结点包含着一个元素<list>;
双端队列(deque) 连续存储的指向不同元素的指针所组成的数组<deque>;
容器适配器
栈(stack) 后进先出的值的排列 <stack>;
队列(queue) 先进先出的值的排列 <queue>;
优先队列(priority_queue) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列 <queue>;
关联式容器
集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序 <set>;
多重集合(multiset) 允许存在两个次序相等的元素的集合 <set>;
映射(map) 由{键,值}对组成的集合,以某种作用于键对上的谓词排列 <map>;
多重映射(multimap) 允许键对有相等的次序的映射 <map>;
1.2.2迭代器
迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集
下面要说的迭代器从作用上来说是最基本的部分,可是理解起来比前两者都要费力一些(至少笔者是这样)。软件设计有一个基本原则,所有的问题都可以通过引进一个间接层来简化,这种简化在STL中就是用迭代器来完成的。概括来说,迭代器在STL中用来将算法和容器联系起来,起着一种黏和剂的作用。几乎STL提供的所有算法都是通过迭代器存取元素序列进行工作的,每一个容器都定义了其本身所专有的迭代器,用以存取容器中的元素。
迭代器部分主要由头文件<utility>,<iterator>和<memory>组成。<utility>是一个很小的头文件,它包括了贯穿使用在STL中的几个模板的声明,<iterator>中提供了迭代器使用的许多方法,而对于<memory>的描述则十分的困难,它以不同寻常的方式为容器中的元素分配存储空间,同时也为某些算法执行期间产生的临时对象提供机制,<memory>中的主要部分是模板类allocator,它负责产生所有容器中的默认分配器。
1.2.3算法
大家都能取得的一个共识是函数库对数据类型的选择对其可重用性起着至关重要的作用。举例来说,一个求方根的函数,在使用浮点数作为其参数类型的情况下的可重用性肯定比使用整型作为它的参数类型要高。而C++通过模板的机制允许推迟对某些类型的选择,直到真正想使用模板或者说对模板进行特化的时候,STL就利用了这一点提供了相当多的有用算法。它是在一个有效的框架中完成这些算法的——你可以将所有的类型划分为少数的几类,然后就可以在模版的参数中使用一种类型替换掉同一种类中的其他类型。
STL提供了大约100个实现算法的模版函数,比如算法for_each将为指定序列中的每一个元素调用指定的函数,stable_sort以你所指定的规则对序列进行稳定性排序等等。这样一来,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能并大大地提升效率。
算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。<algorithm>是所有STL头文件中最大的一个(尽管它很好理解),它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、修改、移除、反转、排序、合并等等。<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。<functional>中则定义了一些模板类,用以声明函数对象。
2 STL容器操作
2.1 Vector
2.1.1向量的介绍
向量 vector 是一种对象实体, 能够容纳许多其他类型相同的元素, 因此又被称为容器。 与string相同, vector 同属于STL(StandardTemplate Library, 标准模板库)中的一种自定义的数据类型, 可以广义上认为是数组的增强版。在使用它时, 需要包含头文件vector, #include<vector>。
2.1.2向量的声明及初始化
vector<int>a ; //声明一个int型向量a vector<int> a(10) ; //声明一个初始大小为10的向量 vector<int> a(10,1) ; //声明一个初始大小为10且初始值都为1的向量 vector<int> b(a) ; //声明并用向量a初始化向量b vector<int> b(a.begin(),a.begin()+3) ; //将a向量中从第0个到第2个(共3个)作为向量b的初始值
除此之外,还可以直接使用数组来初始化向量:
int n[]= {1,2,3,4, 5} ;vector<int>a(n, n+5) ; //将数组n的前5个元素作为向量a的初值vector<int>a(&n[1], &n[4]);//将n[1]-n[4]范围内的元素作为向量a的初值
2.1.3元素的输入及访问
元素的输入和访问可以像操作普通的数组那样, 用cin>>进行输入, cout<<a[n]这样进行输出:
2.1.4实例
#include<iostream>#include<vector>using namespace std ; //使用c++标准程序库三种方法之一 int main() { vector<int> a(10,0) ; //大小为10初值为0的向量a //对其中部分元素进行输入 cin >>a[2]; //第三个数 cin >>a[5];//第六个数 cin >>a[6];//第七个数 //全部输出 int i ; for(i=0; i<a.size(); i++) // a.size() 数组大小 cout<<a[i]<<" " ; return 0 ; }
输入:
1 2 3
输出:
0 0 1 0 0 2 30 0 0
实例:
#include <vector>#include<stdio.h>#include <iostream>using namespace std;int main(){ std::vector<int> vec; for(int i=0;i<100;i++) vec.push_back(i); printf("10:%d\n",vec[10]); printf("size:%d\n",vec.size()); printf("**********************************\n"); std::vector<int>::iterator it =vec.begin()+10; vec.erase(it); printf("10:%d\n",vec[10]); printf("size:%d\n",vec.size()); return 0;}
结果:
10:10
size:100
**********************************
10:11
size:99
2.2 List
2.2.1 list的介绍
Lists将元素按顺序储存在链表中.与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢.list是双向循环链表,每一个元素都知道前面一个元素和后面一个元素。在STL中,list和vector一样,是两个常被使用的容器。和vector不一样的是,list不支持对元素的任意存取。list中提供的成员函数与vector类似,不过list提供对表首元素的操作push_front(前端插入元素)、pop_front,这是vector不具备的。和vector另一点不同的是,list的迭代器不会存在失效的情况,他不像vector会保留备份空间,在超过容量额度时重新全部分配内存,导致迭代器失效;list没有备份空间的概念,出入一个元素就申请一个元素的空间,所以它的迭代器不会失效。
2.2.2构造函数
1)构造函数
list<Elem> c:创建一个空的list;
list<Elem> c1(c2):复制另一个同类型元素的list;
list<Elem>c(n):创建n个元素的list,每个元素值由默认构造函数确定;
list<Elem>c(n,elem):创建n个元素的list,每个元素的值为elem;
list<Elem>c(begin,end):由迭代器创建list,迭代区间为[begin,end);
2)大小、判断函数
Int size() const:返回容器元素个数;
bool empty() const:判断容器是否为空,若为空则返回true;
3) 增加、删除函数
void push_back(const T&x):list元素尾部增加一个元素x;
void push_front(const T&x):list元素首元素钱添加一个元素X;
void pop_back():删除容器尾元素,当且仅当容器不为空;
void pop_front():删除容器首元素,当且仅当容器不为空;
void remove(constT& x):删除容器中所有元素值等于x的元素;
void clear():删除容器中的所有元素;
iterator insert(iterator it,const T& x ):在迭代器指针it前插入元素x,返回x迭代器指针;
void insert(iteratorit,size_type n,const T& x):迭代器指针it前插入n个相同元素x;
void insert(iteratorit,const_iterator first,const_iteratorlast):把[first,last)间的元素插入迭代器指针it前;
iterator erase(iterator it):删除迭代器指针it对应的元素;
iterator erase(iteratorfirst,iterator last):删除迭代器指针[first,last)间的元素;
2.2.3实例
#include<iostream>#include<string>#include<list>usingnamespace std;typedef list<string> LISTSTR;int main(){LISTSTR test;test.push_back("back"); //元素尾部加"back"test.push_back("middle");//元素尾部加"middle"test.push_back("front"); //元素尾部加"front" backmiddle frontcout<<test.front()<<endl; // test里的一个元素cout<<*test.begin()<<endl; // test.begin指向空间的一个值cout<<endl;cout<<test.back()<<endl; //输出最后一个元素cout<<*(test.rbegin())<<endl; //指针指向最后一个元素cout<<endl;test.pop_front(); //删除首元素test.pop_back(); //删除尾元素cout<<test.front()<<endl; //输入首元素return 0;}
结果:
back
back
front
front
middle
removes实例
#include <iostream>#include <map>#include <string>#include <list>using namespace std;int main(){ list<int> numbers; list<int>::iterator number_iter; for ( int number = 0; number <= 6;number ++ ) { numbers.push_back(number); } numbers.push_back(2); numbers.push_back(3); cout<<"size为 "<<numbers.size<<endl; cout<<"remove前 "; for(number_iter = numbers.begin();number_iter != numbers.end(); number_iter++) { cout<< " "<< *number_iter; } cout << endl; numbers.remove(2); cout<<"remove后 "; for(number_iter = numbers.begin();number_iter != numbers.end(); number_iter++) { cout << " "<< *number_iter; } cout << endl; return 0;}
结果:
size为 9
remove前 0 1 2 3 4 5 6 2 3
remove后 0 1 3 4 5 6 3
2.3 Map2.3.1 map的介绍
Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!头文件#include<map>. map是模板,一个map变量key和value两个值,你在这里是想用类似map<int,int> m_map的变量来表示背包里的东西,m_map->first可以取得key值,m_map->second可以取得value值;map自动按照key值按升序排列,key的值不能修改,有且只有一个key,可以修改value的值,value的值可以覆盖。
2.3.2 定义
map<string, int>my_Map; 或者是typedef map<string, int>MY_MAP; MY_MAP my_Map;1)map最基本的构造函数
map<string , int >mapstring; map<int ,string >mapint;map<sring, char>mapstring; map< char ,string>mapchar;map<char ,int>mapchar; map<int ,char >mapint;2)map添加数据
map<int ,string> maplive; //map<int,string>类型,maplive变量名1.maplive.insert(pair<int,string>(102,"aclive"));2.maplive.insert(map<int,string>::value_type(321,"hai"));3.maplive[112]="April"; //map中最简单最常用的插入添加!2.3.3实例
实例:#include<map>#include<iostream>using namespace std ; //使用c++标准程序库三种方法之一int main(){ map<int,string> mapStudent; mapStudent.insert(make_pair(1,"student_one")); mapStudent.insert(pair<int,string>(2,"student_two")); mapStudent.insert(pair<int,string>(3,"student_three")); map<int,string>::iterator iter; for(iter = mapStudent.begin();iter != mapStudent.end();iter++) cout<<iter->first<<" "<<iter->second<<endl; return 0 ;}输出:
1 student_one
2 student_two
3 student_three
3)map中元素的查找
find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
map<int ,string >::iterator l_it; // iterator迭代器
l_it=maplive.find(112);
if(l_it==maplive.end())
cout<<"we do not find 112"<<endl;
else cout<<"wo find 112"<<endl;
实例:
#include<map>#include<iostream>using namespace std ; //使用c++标准程序库三种方法之一int main(){ map<int,string> mapData; mapData.insert(make_pair(1,"SKT1")); mapData.insert(make_pair(2,"SKT2")); for(map<int,string>::iterator l_it = mapData.begin();l_it != mapData.end();l_it++) { l_it = mapData.find(2); if(l_it != mapData.end()) { cout<<"we find 2"<<endl; } else cout<<"we can not find 2"<<endl; break; } return 0 ;}
结果:
we find 2
4)map中元素的删除
如果删除112;
map<int ,string >::iterator l_it;;l_it=maplive.find(112);if(l_it==maplive.end()) cout<<"we do not find 112"<<endl;else maplive.erase(l_it); //delete 112;
实例:
#include <iostream>#include <map>#include <string> using namespace std; int main(){ map<string, string> mapData; map<string ,string >::iterator iter; mapData.insert(make_pair("a","aaa" )); mapData["b"] = "bbb"; mapData["c"] = "ccc"; // // iterator迭代器 /*for(map<string, string>::iterator pIter=mapData.begin(); pIter!=mapData.end();pIter++) { if(pIter->first == "b") { mapData.erase(pIter++); } else pIter++; }*/ mapData.erase("a"); for(iter = mapData.begin();iter !=mapData.end();iter++) { cout<<iter->first<<""<<iter->second<<endl; }}
结果:
b bbb
c ccc
结构体实例:
#include<stdio.h>#include <iostream>#include <map>#include <string>using namespace std;#define MAX_NUMBER_PEOPLE 3 typedef struct stu{ string name; int height;}STU,*PSTU; // 构造数据STUstudents[MAX_NUMBER_PEOPLE] = { {"LiMing", 172}, {"XiaoHua", 160}, {"XiaoWang", 180}}; int main(){ map<int, STU> mapstudent; map<int, STU>::iterator student_iter; mapstudent.insert(pair<int, STU>(172,students[0])); mapstudent.insert(pair<int, STU>(160,students[1])); mapstudent.insert(pair<int, STU>(180,students[2])); mapstudent.erase(160); for(student_iter = mapstudent.begin();student_iter!=mapstudent.end();student_iter++) { cout<<student_iter->first<<""<<student_iter->second.name<<endl; }}
结果:
172 LiMing
180 XiaoWang
2.3.4 map的sort问题
Map中的元素是自动按key升序排序,所以不能对map用sort函数:
sort函数见下表:
实例:
#include <map>#include <iostream>usingnamespace std;int main( ) { map <int, int> m1; map <int,int>::iterator m1_Iter; m1.insert ( pair <int,int> ( 1, 20 ) ); m1.insert ( pair<int, int> ( 4, 40 )); m1.insert ( pair<int, int> ( 3, 60 )); m1.insert ( pair<int, int> ( 2, 50 )); m1.insert ( pair<int, int> ( 6, 40 )); m1.insert ( pair<int, int> ( 7, 30 )); cout << "The original mapm1 is:"<<endl; for ( m1_Iter =m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ ) cout<< m1_Iter->first<<""<<m1_Iter->second<<endl;}
结果:
1 20
2 50
3 60
4 40
6 40
7 30
3.总结
1. Vector的数据模型就是数组
优点:内存和C完全兼容、高效随机访问、节省空间;
缺点:内部插入删除元素代价巨大、动态大小查过自身容量需要申请大量内存做大量拷贝。
2. List的数据结构模型是链表
优点:任意位置插入删除元素常量时间复杂度、两个容器融合是常量时间复杂度;
缺点:不支持随机访问、比vector占用更多的存储空间。
3. Map的数据结构模型是二叉树
优点:元素会按照键值排序、查找是对数时间复杂度、通过键值查元素、map提供了下标访问。
4. List每次增加一个元素,不存在重新申请内存的情况,它的成本是恒定的。而vector每当增加关键元素的时候,都需要重新申请新的更大的内存空间,会调用元素的自身的复制构造函数,存在构造成本。在销毁旧内存的时候,会调用析构函数,存在析构成本。所以在存储复杂类型和大量元素的情况下,list比vector更有优势!
List是一个双向链表,双链表既可以向前又向后链接他的元素。
List将元素按顺序储存在链表中.与向量(vector)相比,它允许快速的插入和删除,但是随机访问却比较慢。
[微信打赏]
- 在cocoa中使用C++STL 链表
- c++STL中优先队列的使用
- C++STL中vector的使用
- c++STL中优先队列的使用
- c++stl中reverse
- c++stl中reverse
- C STL Qsort使用
- c++STL基本使用
- c++STL容器使用
- C++STL中全排列函数next_permutation的使用
- C++STL中全排列函数next_permutation的使用
- C++STL中全排列函数next_permutation的使用
- STL中map使用
- STL中vector使用
- STL中set使用
- C++中STL使用
- C++STL容器使用经验总结
- C++STL容器使用经验总结
- BUG: scheduling while atomic经典bug
- STL-顺序容器-列表list
- Hibernate的五大核心接口
- 小程序如何接入微信支付?你可能会遇上这些坑
- 内部排序算法:冒泡排序
- C++中STL使用
- 《C++ Primer》读书笔记 第16章:模板与泛型编程
- php自动获取字符串编码函数mb_detect_encoding
- npm
- 将CSV文件导入到hive数据库
- require 与inclkude的区别
- Axon VR获VR触觉相关专利,可模拟触摸皮肤的感觉
- 更新android studio 后更新gradle 遇到的坑
- JVM 优化经验总结