c++含义:C语言+类+模板(STL是实例,标准模板库)
STL有六大组件,常用的三个:容器(container),算法(algorithm),迭代器(iterator)
STL好处:节省时间,高移植性,高性能
STL内的所有组件都由模板(template)构成,其元素可以是任意类型
STL是所有C++编译器和所有操作系统平台都支持的一种库
容器:
- 容器是系统帮我们封装好的数据结构(数组,链表【单向链表,双向链表】,栈,队列,数,hash表)
- 每种结构都能装任意类型(模板,泛型编程)
- 主要操作:增删改查
- STL容器类别
序列式容器-排列次序取决于插入时机和位置,vector,list,deque(线性顺序结构)
关联式容器-排列顺序取决于特定准则set ,map(非线性的树结构) - STL容器元素的条件
必须能够通过拷贝构造函数进行复制
必须可以通过赋值运算符完成赋值操作
必须可以通过析构函数完称销毁动作
序列式容器元素的默认构造函数必须可用
某些动作必须定义operator ==,例如搜寻操作
关联式容器必须定义出排序准则,默认情况是重载operator <
对于基本数据类型(int,long,char,double,…)而言,以上条件总是满足 - STL容器的共同操作
(1)初始化(initialization)
//产生一个空容器
std::list<int> l;
//以另一个容器元素为初值完成初始化
std::list<int> l;
…
std::vector<float> c(l.begin(),l.end());
//以数组元素为初值完成初始化
int array[]={2,4,6,1345};
…
std::set<int> c(array,array+sizeof(array)/sizeof(array[0]));
//sizeof(array)/sizeof(array[0])用整个数组所占空间除以第一个元素所占空间,结果为数组元素的个数
(2)与大小相关的操作(size operator)
size()-返回当前容器的元素数量
empty()-判断容器是否为空
max_size()-返回容器能容纳的最大元素数量
(3)比较(comparison)
==,!=,<,<=,>,>=
比较操作两端的容器必须属于同一类型
如果两个容器内的所有元素按序相等,那么这两个容器相等
采用字典式顺序判断某个容器是否小于另一个容器
(4)赋值(assignment)和交换(swap)
(5)与迭代器(iterator)相关的操作
begin()-返回一个迭代器,指向第一个元素
end()-返回一个迭代器,指向最后一个元素之后
//STL区间都是左闭右开
rbegin()-返回一个逆向迭代器,指向逆向遍历的第一个元素
rend()-返回一个逆向迭代器,指向逆向遍历的最后一个元素之后
(6) 元素操作
insert(pos,e)-将元素e的拷贝安插于迭代器pos所指的位置
erase(beg,end)-移除[beg,end]区间内的所有元素
clear()-移除所有元素
string
- 专门字符串操作类
- 与char* 的区别:char* 是指向字符串首地址的指针.然后系统提供了一个string.h头文件,声明了很多字符串操作,如:strlen,strcat,strcmp,srtcpy等。string则是个类,把以上内容封装在一起。string不需要考虑内存分配与释放。
- 头文件:< string >
- 构造函数:
无参数构造函数:string();
有参数构造函数:
string(size_type length,char s);//length个s
string (const char*str);//字符串初始化
string(const char*str,size_type length);//str的前几个
string(string &str,size_type index,size_type length);//中间几个
拷贝构造:
string(const string& str);
string s1;//调用无参构造
string s2(10,'a');
string s3("asdfg");
string s4(s3);//拷贝构造
- 操作
//取值操作
string s1="1234";
//重载[]操作符
for(int i=0;i<s1.size();i++)
{
cout<<s1[i]<<" ";
}
//at成员函数
for(int i=0;i<s1.size();i++)
{
cout<<s1.at(i)<<" ";
}
//at与[]的区别:如果越界,at可以捕获异常,[]不可以
//拼接操作
s1=s2+s3;
s4.append(s2);
查找,替换,比较:
//查找操作
string s="12342";
cout<<s.find("34")<<endl;//find()方法,从前往后找第一次出现的位置
cout<<s.rfind("2");//rfind()方法,从后往前找最后一次出现的位置
//替换操作
string s="12342";
cout<<s.replace(0,2,"aaaa");//结果aaaa342
//比较操作
//compare,>返回1,<返回-1,==返回0
string s1="1111";
string s2="22";
if(s1.compare(s2)==0)
cout<<"字符串相等";
cout<<"不相等";
删除,插入:
//string子串
string s="asdfg";
string s1=s.substr(1,2);
cout<<s1<<endl;//结果sd
vector
- vector模拟动态数组
- 头文件#include < vector>
- vector支持随机存取
- vector的大小(size)和容量(capacity)
size()返回实际元素个数,
capacity()返回vector能容纳的元素最大数量。
如果插入元素时,元素个数超过capacity,需要重新配置内部存储器。
- vector构造、拷贝和析构
- 非变动操作
注意:比较的是向量本身。
- 赋值操作
- 元素存取
- 与迭代器相关的操作
- 安插元素insert
- 移除元素remove
#include <iostream>
int main(){
vector<int> a;
for (int i = 0; i < 5; ++i){
a.push_back(5 - i);
}
cout << a.size() << endl;
a.pop_back();
a[0] = 1;
cout << a.size() << endl;
for (int i = 0; i < (int)a.size(); ++i){
cout << a[i] << ", " << endl;//向量取元素时,可以以数组形式
}
cout << endl;
sort(a.begin(), a.end());//默认升序排序
cout << "Size: " << a.size() << endl;
for (int i = 0; i < (int)a.size(); ++i){
cout << a[i] << ", " << endl;
}
cout << endl;
a.clear();
cout << "Size: " << a.size() << endl;
return 0;
}
map/multimap
- 使用平衡二叉树管理元素
元素包含两部分(key,value),key和value可以是任意类型 - #include < map >
- 根据元素的key自动对元素排序,因此根据元素的key进行定位很快,但根据元素的value定位很慢
- 不能直接改变元素的key,可以通过operator []直接存取元素值
- map中不允许key相同的元素,multimap允许key相同的元素
- 构造、拷贝和析构
map可以是下列形式
map<key,value> 一个以less(<)为排序准则的map(升序),
map<key,value,op> 一个以op为排序准则的map - 非变动操作
- 赋值操作
- 特殊搜寻操作(除equal外,使用较多)
- 迭代器相关函数
- 安插元素
- 删除元素
#include<bits/stdc++.h>
using namespace std;
struct T1{
int v;
bool operator<(const T1 &a)const{
return (v < a.v);
}
};
struct T2{
int v;
};
struct cmp{
const bool operator()(const T2 &a, const T2 &b){
return (a.v < b.v);
}
};
int main(){
map<T1, int>mt1;
map<T2, int, cmp>mt2;
map<string, int> m2;
map<string, int>::iterator m2i, p1, p2;
m2["abd"] = 2;//map对象作为数组使用,下标为key的取值
m2["abc"] = 1;
m2["cba"] = 2;
m2.insert(make_pair("aaa", 9));//成对
m2["abf"] = 4;
m2["abe"] = 2;
cout << m2["abc"] << endl;
m2i = m2.find("cba");
if(m2i != m2.end()){
//first表示取出key,second表示取出value
cout << m2i->first << ": " << m2i->second << endl;
}else{
cout << "find nothing" << endl;
}
cout << "Iterate" << endl;
for(m2i = m2.begin(); m2i != m2.end(); m2i++){
cout << m2i->first << ": " << m2i->second << endl;
}
}
注意:
1.map对象放入元素的方式:
(1)作为数组,数组下标为关键字的取值,可为任意类型。
(2)map对象插入对象使用insert(make_pair())。
2.取出map对象的关键字和值元素,first表示取出key,second表示取出value.
#include<bits/stdc++.h>
using namespace std;
struct T1{
int v;
bool operator<(const T1 &a)const{
return (v < a.v);
}
};
struct T2{
int v;
};
struct cmp{
const bool operator()(const T2 &a, const T2 &b){
return (a.v < b.v);
}
};
int main(){
multimap<string, int> mm1;
//multiple存放关键字相同的若干元素
multimap<string, int>::iterator mm1i, p1, p2;
mm1.insert(make_pair("b", 3));
mm1.insert(make_pair("a", 0));
mm1.insert(make_pair("b", 5));
mm1.insert(make_pair("c", 4));
mm1.insert(make_pair("b", 2));
cout << mm1.size() << endl;
for(mm1i = mm1.begin(); mm1i != mm1.end(); mm1i++){
cout << mm1i->first << ": " << mm1i->second << endl;
}
cout << "COUNT: " << mm1.count("b") << endl;
cout << "Bound: " << endl;
//对满足条件的若干项查找
p1 = mm1.lower_bound("b");//下限
p2 = mm1.upper_bound("b");//上限
for(mm1i = p1; mm1i != p2; mm1i++){
cout << mm1i->first << ": " << mm1i->second << endl;
}
return 0;
}
注意:若要查找多个满足条件的项,先找到满足条件的上下限,再在满足条件的上下限区间中操作(输出)。
set/multiset
- 使用平衡二叉树管理元素
- 集合(Set)是一种包含已排序对象的关联容器。
- 头文件#include < set>
- map容器是键-值对的集合,好比以人名为键的地址和电话号码。相反地,**set容器只是单纯的键的集合。**当我们想知道某位用户是否存在时,使用set容器是最合适。
- set中不允许key相同的元素,multiset允许key相同的元素
#include<bits/stdc++.h>
using namespace std;
struct T1{
int key;
int value1, value2;
bool operator<(const T1 &b)const{
return (key < b.key);
}
};
struct T2{
int key;
int v1, v2;
};
struct T2cmp{
bool operator()(const T2 &a, const T2 &b){
return (a.key < b.key);
}
};
int main(){
set<T1> s2;
set<T2, T2cmp> s3;
#if 1//宏定义条件编译
set<string>s1;
set<string>::iterator iter1;
#else
set<string, greater<string> >s1;//两个>>之间要有空格!!!!!
set<string, greater<string> >::iterator iter1;//greater降序排列
#endif
s1.insert("abc");//set元素取值只能取不相同的
s1.insert("abc");//无效
s1.insert("abc");//无效
s1.insert("bca");
s1.insert("aaa");
cout << "ITERATE:" << endl;
for (iter1 = s1.begin(); iter1 != s1.end(); iter1++)
cout << (*iter1) << endl;
cout << "FIND:" << endl;
iter1 = s1.find("abc");
if(iter1 != s1.end())
cout << *iter1 << endl;
else cout << "NOT FOUND" << endl;
cout << s1.count("abc") << endl;
multiset<string>::iterator s1i, p1, p2;
p1 = s1.lower_bound("abc");
p2 = s1.upper_bound("abc");
for(s1i = p1; s1i != p2; s1i++){
cout << (*s1i) << endl;
}
return 0;
}
结果:
ITERATE:
aaa
abc
bca
FIND:
abc
1
abc
注意:multiple可以允许插入值相同的元素,set中不能有值相同的元素。
pair 模板:
pair模板可以用于生成 key-value对。
#include <set>
#include <iostream>
using namespace std;
int main() {
typedef set<double,less<double> > double_set;
const int SIZE = 5;
double a[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
double_set doubleSet(a,a+SIZE);//数组元素初始化,把a中数据放入double_set中
ostream_iterator<double> output(cout," ");
//输出流对象迭代器
cout << "1) ";
copy(doubleSet.begin(),doubleSet.end(),output);
cout << endl;
pair<double_set::const_iterator, bool> p;
p = doubleSet.insert(9.5); //插入不进去,已有9.5
if( p.second )
cout << "2) " << * (p.first) << " inserted" << endl;
else
cout << "2) " << * (p.first) << " not inserted" << endl;
}
//insert函数返回值是一个pair对象, 其first是被插入元素的迭代器,second代表是否成功插入了
#include <iostream>
#include <map>
using namespace std;
ostream & operator <<( ostream & o,const pair< int,double> & p)
{
o << "(" << p.first << "," << p.second << ")";
return o;
}
int main() {
typedef map<int,double,less<int> > mmid;
mmid pairs;
cout << "1) " << pairs.count(15) << endl;
pairs.insert(mmid::value_type(15,2.7));
pairs.insert(make_pair(15,99.3)); //make_pair生成一个pair对象
cout << "2) " << pairs.count(15) << endl;
pairs.insert(mmid::value_type(20,9.3));
mmid::iterator i;
cout << "3) ";
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
cout << endl;
cout << "4) ";
int n = pairs[40];//如果没有关键字为40的元素,则插入一个
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
cout << endl;
cout << "5) ";
pairs[15] = 6.28; //把关键字为15的元素值改成6.28
for( i = pairs.begin(); i != pairs.end();i ++ )
cout << * i << ",";
}
迭代器:
链接容器和算法.可以理解为容器中元素的指针。
迭代器对象必须与容器类型相匹配
-
可遍历STL容器内全部或部分元素的对象
-
指出容器中的一个特定位置
-
迭代器的基本操作
-
所有容器都提供获得迭代器的函数
半开区间[beg, end)的好处:
1.为遍历元素时循环的结束时机提供了简单的判断依据(只要未到达end(),循环就可以继续)
2.不必对空区间采取特殊处理(空区间的begin()就等于end()) -
所有容器都提供两种迭代器
container::iterator以“读/写”模式遍历元素
container::const_iterator以“只读”模式遍历元素 -
迭代器分类
(1)双向迭代器
双向行进,以递增运算前进或以递减运算后退、可以用==和!=比较。
list、set和map提供双向迭代器
list<int> l;
for(pos=l.begin();pos!=l.end();++pos{
…
}
(2)随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量、处理迭代器之间的距离或者使用<和>之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器
vector<int> v;
for(pos=v.begin();pos<v.end();++pos{
…
}
算法:
- 系统帮我们写好的算法(排序,交换,替换等)
- 一个算法可以适用多个容器(如,sort可以给数组排序,也可以给链表排序)
- 泛型算法通则
所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。 - 常用算法:
count:
size_t count(InIt first, InIt last, const T& val);
计算[first,last) 中等于val的元素个数
count_if
size_t count_if(InIt first, InIt last, Pred pr);
计算[first,last) 中符合pr(e) == true 的元素 e的个数
min_element:
template<class FwdIt>
FwdIt min_element(FwdIt first, FwdIt last);
返回[first,last) 中最小元素的迭代器,以 “< ”作比较器
max_element:
for_each
Fun for_each(InIt first, InIt last, Fun f); 对指定区间内的元素遍历
#include <vector>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
using namespace std;
class CLessThen9 {
public:
bool operator()( int n) { return n < 9; }
};//<9返回true
void outputSquare(int value ) { cout << value * value << " "; }
}
main() {
const int SIZE = 10;
int a1[] = { 100,2,8,1,50,3,8,9,10,2 };
vector<int> v(a1,a1+SIZE);
ostream_iterator<int> output(cout," ");
cout << endl << "2)";
cout << count(v.begin(),v.end(),8);//数值为8的元素有几个
cout << endl << "3)";
cout << count_if(v.begin(),v.end(),CLessThen9());//<9的有几个
cout << endl << "4)";
cout << * (min_element(v.begin(),v.end()));
cout << endl << "5)";
cout << * (max_element(v.begin(),v.end()));
cout << endl << "7) ";
for_each(v.begin(),v.end(),outputSquare);
}
排序和查找算法
find(不属于某个容器对象的算法)
template<class InIt, class T>
InIt find(InIt first, InIt last, const T& val); value重载了=运算符
返回区间 [first,last) 中的迭代器 i ,使得 * i == val
find_if
template<class InIt, class Pred>
InIt find_if(InIt first, InIt last, Pred pr); 带条件的查询
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
binary_search 折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到
lower_bound:
要求[first,last)是有序的,
查找大于等于val的最小的位置
upper_bound
要求[first,last)是有序的,
查找大于val的最小位置
equal_range
要求[first,last)是有序的,
返回值是一个pair, 假设为 p, 则
[first,p.first) 中的元素都比 val 小
[p.second,last)中的所有元素都比 val 大
sort 快速排序,升序
reverse 颠倒区间[first,last)顺序
unique 改变序列的算法
#include <vector>
#include <bitset>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
using namespace std;
bool Greater10(int n)
{
return n > 10;
}
main() {
const int SIZE = 10;
int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
vector<int> v(a1,a1+SIZE);
ostream_iterator<int> output(cout," ");
vector<int>::iterator location;
location = find(v.begin(),v.end(),10);
if( location != v.end()) {
cout << endl << "1) " << location - v.begin();
}//元素在向量中的位置
location = find_if( v.begin(),v.end(),Greater10);
if( location != v.end())
cout << endl << "2) " << location - v.begin();
sort(v.begin(),v.end());//先排序
if( binary_search(v.begin(),v.end(),9)) {
cout << endl << "3) " << "9 found";
}
}
集合算法
#include "stdafx.h"
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator>
using namespace std;
template <class T>
struct display
{
void operator()(const T&x) const
{
cout << x << " ";
}
};
int main(int argc, char* argv[])
{
int iarr1[] = { 1, 3, 5, 7, 9, 11 };
int iarr2[] = { 1, 1, 2, 3, 5, 8, 13 };
multiset<int> s1(iarr1, iarr1 + 6);
multiset<int> s2(iarr2, iarr2 + 7);
cout << "s1: ";
for_each(s1.begin(), s1.end(), display<int>());
cout << endl;
cout << "s2: ";
for_each(s2.begin(), s2.end(), display<int>());
cout << endl;
/*** set_union: 构造一个有序序列,包含两个序列中所有的不重复元素。 ***/
// 原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
cout << "union of s1 and s2: ";
// 两个集合合并,相同元素个数取 max(m,n)。
set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
/*** set_intersection: 构造一个有序序列,其中元素在两个序列中都存在。 ***/
// 原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
cout << "Intersection of s1 and s2: ";
// 两个集合交集,相同元素个数取 min(m,n).
set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
/*** set_difference: 构造一个有序序列,该序列仅保留第一个序列中存在的而第二个中不存在的元素。 ***/
// 原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
cout << "Intersection of s1 and s2: ";
// 两个集合差集 就是去掉S1中 的s2
set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
/*** set_symmetric_difference: 构造一个有序序列,该序列取两个序列的对称差集(并集-交集)。 ***/
// 原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
cout << "Intersection of s1 and s2: ";
// 两个集合对称差集:就是取两个集合互相没有的元素 。两个排序区间,元素相等指针后移,不等输出小的并前进
// 相同元素的个数 abs(m-n)
set_symmetric_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
cout << endl;
return 0;
}
/*
s1: 1 3 5 7 9 11
s2: 1 1 2 3 5 8 13
union of s1 and s2: 1 1 2 3 5 7 8 9 11 13
Intersection of s1 and s2: 1 3 5
Intersection of s1 and s2: 7 9 11
Intersection of s1 and s2: 1 2 7 8 9 11 13
*/
注意:
查找操作:
(1)精确查找
(2)模糊查找
(向量的按条件查找(效率较低))
- 使用不完全的关键字。(对map对象的谓词函数中find_if())。
- 区间查找:先找low_bound和up_bound,再操作区间里的元素。
- 组合查找:多关键字查找。(满足条件较少的关键字,先作为第一关键字。)重合部分可以用集合算法(交集)。
学习感想:
经过这段时间的学习我对STL也有了大体的了解,但是STL内容掌握还不够熟练,内容还需要熟悉,多练习。接下来就要经过大量的训练来进一步扎实STL的运用。
最近学习状态有所松懈,作息也不够规律,还需调整提高效率。