C++的STL总结(1)
没有很系统的学过算法,c++也只是学些基础,虽然经常会用一些STL里面的函数,但是并没有对STL模板库有一个清晰的了解,趁着寒假有时间就自己在网上百度浏览别人的总结的内容,自己汇集并总结了一下,希望对自己以后的路能有所帮助。
一:STL简介
STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。现在虽说它主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
二:容器
在实际的开发过程中,数据结构本身的重要性不会逊于操作于数据结构的算法的重要性,当程序中存在着对时间要求很高的部分时,数据结构的选择就显得更加重要。经典的数据结构数量有限,但是我们常常重复着一些为了实现向量、链表等结构而编写的代码,这些代码都十分相似,只是为了适应不同数据的变化而在细节上有所出入。STL容器就为我们提供了这样的方便,它允许我们重复利用已有的实现构造自己的特定类型下的数据结构,通过设置一些模版类,STL容器对最常用的数据结构提供了支持,这些模板的参数允许我们指定容器中元素的数据类型,可以将我们许多重复而乏味的工作简化。
容器部分主要由头文件<vector>,<list>,<deque>,<set>,<map>,<stack>和<queue>组成。对于常用的一些容器和容器适配器(可以看作由其它容器实现的容器),可以通过下表总结一下它们和相应头文件的对应关系。
向量(vector) 连续存储的元素<vector>
列表(list) 由节点组成的双向链表,每个结点包含着一个元素<list>
双队列(deque) 连续存储的指向不同元素的指针所组成的数组<deque>,可以在头和尾都可以插入和删除
集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序 <set>
多重集合(multiset) 允许存在两个次序相等的元素的集合 <set>
栈(stack) 后进先出的值的排列 <stack>
队列(queue) 先进先出的执的排列 <queue>
优先队列(priority_queue) 元素的次序是由作用于所存储的值对上的某种谓词决定的的一种队列 <queue>
映射(map) 由{键,值}对组成的集合,以某种作用于键对上的谓词排列 <map>
多重映射(multimap) 允许键对有相等的次序的映射 <map>
三:迭代器
概括来说,迭代器在STL中用来将算法和容器联系起来,起着一种黏和剂的作用。几乎STL提供的所有算法都是通过迭代器存取元素序列进行工作的,每一个容器都定义了其本身所专有的迭代器,用以存取容器中的元素。迭代器部分主要由头文件<utility>,<iterator>和<memory>组成。
四:常用库函数总结
(1)C++迭代器
正文:
迭代器是一种检查容器内元素并遍历元素的数据类型。C++更趋向于使用迭代器而不是下标操作,因为标准库为每一种标准容器(如vector)定义了一种迭代器类型,而只用少数容器(如vector)支持下标操作访问容器元素。
定义和初始化:
每种容器都定义了自己的迭代器类型,如vector:
vector<int>::iterator iter; //定义一个名为iter的变量
每种容器都定义了一对名为begin和en的函数,用于返回迭代器。下面对迭代器进行初始化操作:
vector<int> ivec;
vector<int>::iterator iter1=ivec.bengin(); //将迭代器iter1初始化为指向ivec容器的第一个元素 vector<int>::iterator iter2=ivec.end(); //将迭代器iter2初始化为指向ivec容器的最后一个元素的下一个位置
注意end并不指向容器的任何元素,而是指向容器的最后元素的下一位置,称为超出末端迭代器。如果vector为空,则begin返回的迭代器和end返回的迭代器相同。一旦向上面这样定义和初始化,就相当于把该迭代器和容器进行了某种关联,就像把一个指针初始化为指向某一空间地址一样。
常用操作
*iter //对iter进行解引用,返回迭代器iter指向的元素的引用
iter->men //对iter进行解引用,获取指定元素中名为men的成员。等效于(*iter).men
++iter //给iter加1,使其指向容器的下一个元素
iter++
--iter //给iter减1,使其指向容器的前一个元素
iter--
iter1==iter2 //比较两个迭代器是否相等,当它们指向同一个容器的同一个元素或者都指向同同一个容器的超出末端的下一个位置时,它们相等
iter1!=iter2
假设已经声明一个vector<int>的ivec容器,下面用迭代器来遍历ivec容器,把其每个元素重置为0:
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter) *iter=;
在C++定义的容器类型中,只有vector和queue容器提供迭代器算数运算和除!=和==之外的关系运算:
iter+n //在迭代器上加(减)整数n,将产生指向容器中钱前面(后面)第n个元素的迭代器。新计算出来的迭代器必须指向容器中的元素或超出容器末端的下一个元素
iter-n iter1+=iter2 //将iter1加上或减去iter2的运算结果赋给iter1。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素
iter1-=iter2 iter1-iter2 //两个迭代器的减法,得出两个迭代器的距离。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素 >,>=,<,<= //元素靠后的迭代器大于靠前的迭代器。两个迭代器必须指向容器中的元素或超出容器末端的下一个元素
注意两个迭代器相减得出两个迭代器对象的距离,该距离名为difference_type的signed类型的值,该类型类似于size_type类型,也是有vector定义的。可以迭代器算术操作来移动迭代器直接指向某个元素:
vector<int>::iterator mid=v.begin()+v.size()/; //初始化mid迭代器,使其指向v中最靠近正中间的元素
迭代器const_iterator
每种容器还定义了一种名为const_iterator的类型。该类型的迭代器只能读取容器中的元素,不能用于改变其值。之前的例子中,普通的迭代器可以对容器中的元素进行解引用并修改,而const_iterator类型的迭代器只能用于读不能进行重写。例如可以进行如下操作:
for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)
cout<<*iter<<endl; //合法,读取容器中元素值 for(vector<int>::const_iterator iter=ivec.begin();iter!=ivec.end();++iter)
*iter=; //不合法,不能进行写操作
const_iterator和const iterator是不一样的,后者对迭代器进行声明时,必须对迭代器进行初始化,并且一旦初始化后就不能修改其值。这有点像常量指针和指针常量的关系。例如:
vector<int> ivec();
const vector<int>::iterator iter=ivec.begin();
*iter=; //合法,可以改变其指向的元素的值
++iter; //不合法,无法改变其指向的位置
使迭代器失效的操作
由于一些对容器的操作如删除元素或移动元素等会修改容器的内在状态,这会使得原本指向被移动元素的迭代器失效,也可能同时使其他迭代器失效。使用无效的迭代器是没有定义的,可能会导致和使用悬垂指针相同的问题。所以在使用迭代器编写程序时,需要特别留意哪些操作会使迭代器失效。使用无效迭代器会导致严重的运行时错误。
(2)求和(<numeric> accumulate)
#include <iostream>
#include <vector>
#include <numeric> using namespace std; int main()
{
vector<int> v;
for(int i = ; i < ; ++i )
{
v.push_back(i);
}
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
cout << accumulate(v.begin(),v.end(),) << endl;
return ;
}
(3)vector(动态数组)
vector 是向量类型,它可以容纳许多类型的数据,如若干个整数,所以称其为容器。vector 是C++ STL的一个重要成员,使用它时需要包含头文件:
#include<vector>;
一、vector 的初始化:可以有五种方式,举例说明如下:
(1) vector<int> a(10); //定义了10个整型元素的向量(尖括号中为元素类型名,它可以是任何合法的数据类型),但没有给出初值,其值是不确定的。
(2)vector<int> a(10,1); //定义了10个整型元素的向量,且给出每个元素的初值为1
(3)vector<int> a(b); //用b向量来创建a向量,整体复制性赋值
(4)vector<int> a(b.begin(),b.begin+3); //定义了a值为b中第0个到第2个(共3个)元素
(5)int b[7]={1,2,3,4,5,9,8};
vector<int> a(b,b+7); //从数组中获得初值
二、vector对象的几个重要操作,举例说明如下:
(1)a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
(2)a.assign(4,2); //是a只含4个元素,且每个元素为2
(3)a.back(); //返回a的最后一个元素
(4)a.front(); //返回a的第一个元素
(5)a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
(6)a.clear(); //清空a中的元素
(7)a.empty(); //判断a是否为空,空则返回ture,不空则返回false
(8)a.pop_back(); //删除a向量的最后一个元素
(9)a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+ 3(不包括它)
(10)a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
(11)a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
(12)a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
(13)a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8 ,插入元素后为1,4,5,9,2,3,4,5,9,8
(14)a.size(); //返回a中元素的个数;
(15)a.capacity(); //返回a在内存中总共可以容纳的元素个数
(16)a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
(17)a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
(18)a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才 显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
(19)a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
(20)a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
三、顺序访问vector的几种方式,举例说明如下:
(1)向向量a中添加元素
1、
1 vector<int> a;
2 for(int i=0;i<10;i++)
3 a.push_back(i);
2、也可以从数组中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
for(int i=1;i<=4;i++)
b.push_back(a[i]);
3、也可以从现有向量中选择元素向向量中添加
int a[6]={1,2,3,4,5,6};
vector<int> b;
vector<int> c(a,a+4);
for(vector<int>::iterator it=c.begin();it<c.end();it++)
b.push_back(*it);
4、也可以从文件中读取元素向向量中添加
ifstream in("data.txt");
vector<int> a;
for(int i; in>>i)
a.push_back(i);
5、【误区】
vector<int> a;
for(int i=0;i<10;i++)
a[i]=i;
//这种做法以及类似的做法都是错误的。刚开始我也犯过这种错误,后来发现,下标只能用于获取已存在的元素,而现在的a[i]还是空的对象
( 2)从向量中读取元素
1、通过下标方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(int i=0;i<=b.size()-1;i++)
cout<<b[i]<<" ";
2、通过遍历器方式读取
int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);
for(vector<int>::iterator it=b.begin();it!=b.end();it++)
cout<<*it<<" ";
四、几种重要的算法,使用时需要包含头文件:
#include<algorithm>
(1)sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
(2)reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
(3)copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素
(4)find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
vector有内存管理的机制,也就是说对于插入和删除,vector可以动态调整所占用的内存空间。
#include <iostream>
#include <vector> using namespace std; int main()
{
vector<int> v;
v.push_back(); //数组尾部插入3
v.push_back();
v.push_back();
v.push_back();
cout << " 下标 " << v[] << 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(),);
//在最后一个元素之后插入222 insert end + n 是在n个元素之后插入
v.insert(v.end(),); for(vector<int>::iterator i = v.begin();i!= v.end();++i)
{
cout << *i << " ";
}
cout << endl; vector<int> arr();
for(int i = ; i < ; 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()+); for(vector<int>::iterator i = arr.begin();i!= arr.end();++i)
{
cout << *i << " " ;
}
cout << endl ;
return ;
}
(4)数组转置 (<algorithm> reverse)
reverse(v.begin(),v.end())
#include<iostream>
#include<vector>
#include<algorithm> using namespace std; int main()
{
vector<int> v;
for(int i = ; i < ; ++i)
{
v.push_back(i);
}
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl; reverse(v.begin(),v.end()); for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
return ;
}
(5)排序(<algorithm> sort)
sort(v.begin(),v.end())
#include<iostream>
#include<vector>
#include<algorithm> using namespace std; bool Comp(const int &a,const int &b)
{
return a>b;
} int main()
{
vector<int> v;
v.push_back();
v.push_back();
v.push_back();
v.push_back();
v.push_back(-);
v.push_back();
v.push_back();
v.push_back();
v.push_back(); for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl; //默认升序
sort(v.begin(),v.end()); for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl; //用降序 需要自定义一个降序函数
sort(v.begin(),v.end(),Comp); for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
cout << endl; return ;
}
(6)字符串(<string>)
输入
#include<iostream>
#include<string>
#include<cstdio> using namespace std; int main()
{
string s1;
s1 = "hello"; string s2;
char s[];
//scanf 输入速度比cin快的多
//scanf 是C函数,不可以输入string
scanf("%s",s);
s2 = s; cout << s1 << endl;
cout << s2 << endl; return ;
}
尾部添加字符字符串直接用+号 例如: s += 'a'; s += "abc",或者使用append方法,s.append(“123”)
(7)删除 (erase clear)
s.erase(it + 1,it + 4); clear()
#include<iostream>
#include<string> using namespace std; int main()
{
string s;
s = "";
cout << s << endl; string::iterator it = s.begin(); //删除s[3]
s.erase(it+);
cout << s << endl; //删除s[1]~s[3]
s = "";
s.erase(it + ,it + );
cout << s << endl; //全部删除
s.clear();
cout << "clear : " << s << endl; return ;
}
(8)查找(find)
用find找到string里面第一个要找到元素(char或者串),找到返回数组下标,找不到返回end()迭代器
string和vector有很多相同的东西,比如length(),size(),empty(),reverse(),相对也容易,就不一一说了。
(9)数字化处理(string)
经常会遇到这样一种情况,有一个数字,需要把每一位给提取出来,如果用取余数的方法,花费的时间就会很长,所以可以当成字符串来处理,方便、省时。
例子:求一个整数各位数的和
#include<iostream>
#include<string> using namespace std; int main()
{
string s;
s = "";
int sum = ;
for(int i = ; i < s.size(); ++i)
{
switch(s[i])
{
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
case '': sum += ;break;
}
} cout << sum << endl; return ;
}
(10)string与char *
#include<iostream>
#include<string>
#include<cstdio> using namespace std; int main()
{
string s_string;
char s_char[];
scanf("%s",s_char); s_string = s_char; //printf输出char* 时用c_str处理
printf(s_string.c_str());
cout << endl; printf("%s",s_char);
cout << endl; cout << s_char << endl;
cout << s_string << endl;
return ;
}
(11)sscanf
#include<iostream>
#include<string>
#include<cstdio> using namespace std; int main()
{
string s1,s2,s3;
char sa[],sb[],sc[];
sscanf("abc 123 wcd","%s%s%s",sa,sb,sc);
s1 = sa;
s2 = sb;
s3 = sc;
cout << s1 << " " << s2 << " " << s3 << endl; //将字符串分离成数字,分隔符为',''$'
int a,b,c;
sscanf("4,5$6","%d,%d$%d",&a,&b,&c);
cout << a << " " << b << " " << c << endl;
return ;
}
(12)string与数值相互转换( sprintf <sstream> )
#include<iostream>
#include<string>
#include<sstream>
#include<cstdio> using namespace std; //c++ 方法 把数转换为string
string converToString(double x)
{
ostringstream o;
if( o << x)
{
// str()没有'\0' c_str有
return o.str();
}
return "error";
} double converFromString(const string &s)
{
istringstream i(s);
double x;
if( i >> x)
{
return x;
}
//if error
return 0.0;
}
int main()
{
char b[];
string s1; //c语言方法
sprintf(b,"%d",);
s1 = b;
cout << s1 << endl; string s2 = converToString();
cout << s2 << endl; string s3 = "";
int c = converFromString(s3);
cout << c << endl; string s4 = "casacsa6";
int d = converFromString(s4);
cout << d << endl; string s5 = "21abf4";
int f = converFromString(s5);
cout << f << endl; return ;
}
参考:http://www.cnblogs.com/Nonono-nw/p/3462183.html
https://www.cnblogs.com/CnZyy/p/3317999.html
C++的STL总结(1)的更多相关文章
- 详细解说 STL 排序(Sort)
0 前言: STL,为什么你必须掌握 对于程序员来说,数据结构是必修的一门课.从查找到排序,从链表到二叉树,几乎所有的算法和原理都需要理解,理解不了也要死记硬背下来.幸运的是这些理论都已经比较成熟,算 ...
- STL标准模板库(简介)
标准模板库(STL,Standard Template Library)是C++标准库的重要组成部分,包含了诸多在计算机科学领域里所常见的基本数据结构和基本算法,为广大C++程序员提供了一个可扩展的应 ...
- STL的std::find和std::find_if
std::find是用来查找容器元素算法,但是它只能查找容器元素为基本数据类型,如果想要查找类类型,应该使用find_if. 小例子: #include "stdafx.h" #i ...
- STL: unordered_map 自定义键值使用
使用Windows下 RECT 类型做unordered_map 键值 1. Hash 函数 计算自定义类型的hash值. struct hash_RECT { size_t operator()(c ...
- C++ STL简述
前言 最近要找工作,免不得要有一番笔试,今年好像突然就都流行在线笔试了,真是搞的我一塌糊涂.有的公司呢,不支持Python,Java我也不会,C有些数据结构又有些复杂,所以是时候把STL再看一遍了-不 ...
- codevs 1285 二叉查找树STL基本用法
C++STL库的set就是一个二叉查找树,并且支持结构体. 在写结构体式的二叉查找树时,需要在结构体里面定义操作符 < ,因为需要比较. set经常会用到迭代器,这里说明一下迭代器:可以类似的把 ...
- STL bind1st bind2nd详解
STL bind1st bind2nd详解 先不要被吓到,其实这两个配接器很简单.首先,他们都在头文件<functional>中定义.其次,bind就是绑定的意思,而1st就代表fir ...
- STL sort 函数实现详解
作者:fengcc 原创作品 转载请注明出处 前几天阿里电话一面,被问到STL中sort函数的实现.以前没有仔细探究过,听人说是快速排序,于是回答说用快速排序实现的,但听电话另一端面试官的声音,感觉不 ...
- STL的使用
Vector:不定长数组 Vector是C++里的不定长数组,相比传统数组vector主要更灵活,便于节省空间,邻接表的实现等.而且它在STL中时间效率也很高效:几乎与数组不相上下. #include ...
- [C/C++] C/C++延伸学习系列之STL及Boost库概述
想要彻底搞懂C++是很难的,或许是不太现实的.但是不积硅步,无以至千里,所以抽时间来坚持学习一点,总结一点,多多锻炼几次,相信总有一天我们会变得"了解"C++. 1. C++标准库 ...
随机推荐
- 单机版 RedisUtils({基本操作封装工具类})【三】
<!--集成的RedisJAR--> <!--引入jedis需的jar包--> <dependency> <groupId>redis.clients& ...
- 分享知识-快乐自己:关于 String 小案例
单个字符出现的次数: /*** * 验证是否符合拆分条件 * * @param text * 原字符串 * @param sub * 判断条件 * @return */ public static i ...
- json-lib的一些过滤操作
package demo4; import java.io.Serializable; import net.sf.json.JSONString; public class User impleme ...
- hdu-1286 找新朋友(欧拉函数,水题)
题目链接: 找新朋友 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
- python字符串相关操作
字符串搜索相关搜索指定字符串,没有返回-1:str.find('t')指定起始位置搜索:str.find('t',start)指定起始及结束位置搜索:str.find('t',start,end)从右 ...
- 错误名称:Uncaught SyntaxError: Unexpected identifier
控制台输出: 1.谷歌:Uncaught SyntaxError: Unexpected identifier 2.火狐:SyntaxError: missing ] after element li ...
- 霍夫变换Hough
http://blog.csdn.net/sudohello/article/details/51335237 霍夫变换Hough 霍夫变换(Hough)是一个非常重要的检测间断点边界形状的方法.它通 ...
- iOS+PHP图片上传
这篇博客用于实现iOS客户端通过POST请求,将图片上传到服务器上.服务器端语言采用PHP,服务器环境使用MAMP搭建.先使用浏览器测试图片是否可以上传,浏览器测试成功之后再测试iOS客户端是否可以成 ...
- Starting MySQL....The server quit without updating PID file错误解决办法
出现错误:Starting MySQL....The server quit without updating PID file 检查错误文件: /var/lib/mysql/xxxx.err,根据其 ...
- 【转】 Pro Android学习笔记(五八):Preferences(2):CheckBoxPreference
目录(?)[-] CheckBox Preference xml文件 设备的存贮文件 复合preference 在ListPreference的例子中显示的是单选,如果是多选,可采用CheckBoxP ...