www.2527.com_澳门新葡8455手机版_新京葡娱乐场网址_
做最好的网站

师傅和徒弟恋大法好,你看本人就够了

2019-09-23 00:02 来源:未知

有了STL,不必再起来写多数的正规数据结议和算法,并且可获取极高的质量。(若无氩气,最佳不用用vector,deque,set,multiset,map,string)。

1.STL

STL(标准模板库),是现阶段C 内置协助的library。它的后面部分利用了C 类模板和函数模板的建制,由三大片段构成:容器、算法和迭代器。

废话相当的少说,让大家一道会见STL到底有多好用。

  [1]STL容器是一贯管制存款和储蓄数据。

此时此刻STL有六大组件

1.vector

可变长度的数组。

常用操作:

#include<vector>vector<int>a;a[i];//重载了[],返回数组的第i 1个元素a.empty()//数组为空返回1,否则返回0a.size()//返回数组元素个数a.push_back//尾部插入元素xa.pop_back()//删除尾部元素a.begin()//返回第一个元素迭代器a.end()//返回最后一个元素迭代器

地方的操作时间复杂度均为O;(但常数大,比数组慢,唯有吸氧技巧和数组媲美)

上面包车型客车操作慎用:

a.erase//删除迭代器it1到it2的元素a.erase//删除迭代器it指向的元素a.clear();//清空数组a.insert//在迭代器为it的位置加入x,其他后移a.assign,b.end//把vector b复制到vector a

那些操作时间复杂度为O,且常数十分的大。

vector帮助algorithm库中的有些操作,如:

sort,a.end;//排序,cmp是自定义函数。lower_bound,a.end;//返回数组中第一个大于等于x的元素的迭代器。upper_bound,a.end//返回数组中第一个大于x的元素的迭代器。max_element,a.end//返回数组最大值min_element,a.end//返回数组最小值random_shuffle,a.end//随机打乱,在随机化算法中用到。reverse,a.end//数组反转

留意:未有氧气,慎用vector

上边通过几道例题感受vector的便民。

例题1:洛谷P1177快速排序

就算能够用sort,但大家尝试使用vector来达成。

#include<bits/stdc  .h>std::vector<int>a;int main(){    int n,x;    scanf("%d",&n);    for(register int i=0;i<n;  i)scanf("%d",&x),a.insert(upper_bound,a.end;    for(register int i=0;i<n;  i)printf("%d ",a[i]);    return 0;}

从地方能够观望,vector能够充裕省事地支撑插排。

例题2:P3378 堆

虽说能够利用另八个器皿priority_queue,但我们得以行使vector切了它。

#include<bits/stdc  .h>std::vector<int>a;int main(){    int n,k,x;    scanf("%d",&n);    for(register int i=1;i<=n;  i){        scanf("%d",&k);        if{            scanf("%d",&x);            a.insert(upper_bound,a.end;        }        else ifprintf("%dn",a[0]);        else a.erase);    }    return 0;}

从上边两道例题能够看到,vector的操作也不自然慢,可是最为注意程序的常数,能开O2尽量开

例题3:洛谷P3369 普通平衡树

此题是上述操作的汇总,不要以为数组很菜,它能支平树的操作呢。

#include<bits/stdc  .h>std::vector<int>a;int main(){    int n,opt,x;    scanf("%d",&n);    for(register int i=1;i<=n;  i){        scanf("%d%d",&opt,&x);        ifa.insert(upper_bound,a.end;        else ifa.erase(lower_bound,a.end;        else ifprintf("%dn",lower_bound,a.end-a.begin;        else ifprintf("%dn",a[x-1]);        else ifprintf("%dn",*(lower_bound,a.end;        else printf("%dn",*(upper_bound,a.end;    }    return 0;}

从第一个容器就能看出师徒恋的方便了吧

  [2]STL适配器是在那一个器皿上边扩张部分操作函数,封装成四个模板。

  • 容器 container
  • 算法 algorthm
  • 迭代器 iterator
  • 仿函数 function object
  • 适配器 adaptor
  • 空间配置器 allocator

2.stack

常用操作:

#include<stack>stack<int>st;st.push//向栈顶加入x,Ost.pop()//栈顶出栈,Ost.top()//返回栈顶,O

看出来了啊?stack的持有操作vector都能支持。

但栈的想想很要紧,后缀表明式,tarjan强连通分量算法以及单调栈等都供给用到。

此处给我们推荐一道单调栈例题,感受一下单调栈

例题:洛谷SP1805 HISTOGRA - Largest Rectangle in a Histogram

设若矩形从左到右单调递增,答案是以每种矩形的惊人为中度,从当下矩形到侧面界为宽度的矩形的面积的最大值

倘诺下三个比上二个矮,那么那块矩形和事先的矩形构成十分大范围时,新矩形中度不容许当先此矩形中度,所以能够把比此矩形高的矩形删掉,用宽度不改变,中度为此矩形中度的矩形代替

轻便易行说,大家保卫安全多个栈,保存中度单调递增的矩形,然后扫描种种矩形,假若比栈顶矩形高,进栈,不然栈顶出栈直至栈空或栈顶矩形比近年来矩形矮

#include<bits/stdc  .h>long long n,p,a[100001],w[100001],ans,kd;std::stack<long long>st;int main(){    while(scanf("%lld",&n)&&n){        for(register long long i=1;i<=n;  i)scanf("%lld",&a[i]);        a[n 1]=0;st.push;ans=0;//注意栈为空时.top()会出错,a[n 1]=0避免结束后栈中还有矩形        for(register long long i=1;i<=n 1;  i)            if(a[i]>st.topst.push,w[st.size()]=1;//比栈顶矩形高            else{//否则更新答案                kd=0;                while>a[i])kd =w[st.size()],ans=std::max(ans,kd*st.top,st.pop();                st.push;w[st.size()]=kd 1;            }        printf("%lldn",ans);    }    return 0;}

那正是单调栈,O,借助单调性,能即时消除不恐怕接纳,保持高度有效性和秩序性。

2.STL 容器

上面,大家会相继实行介绍。

3.queue

循环队列

常用操作:

#include<queue>queue<int>q;q.push//队尾加入xq.pop()//队首出队q.front()//返回队首q.back()//返回队尾q.empty()//队列为空返回1否则返回0q.size()//返回队列大小

循环队列的操作都是O的,何况常数相当小,使用方便。

循环队列一般用于广搜,树和图的广度优先遍历,拓扑排序和SPFA等算法中。

树和图的广度优先遍历:

inline void bfs(){    memset(d,0,sizeof;//d数组记录点在树中的深度或点在图中的层次。    queue<int>q;    q.push;d[1]=1;    whiel(!q.empty{        int x=q.front;        for(register int i=head[x];i;i=edge[i].next){//链式前向星存边            if(d[edge[i].to])continue;            d[edge[i].to]=d[x] 1;q.push(edge[i].to);        }    }}

广搜在骗分博客中会详讲。此处略

拓扑排序:

#include<bits/stdc  .h>int x,n,m,deg[1000001],head[1000001],u,v,a[1000001],cnt;struct Edge{int next,to;}edge[1000001];inline void topsort(){    queue<int>q;    for(register int i=1;i<=n;  i)ifq.push;    while(!q.empty{        int x=q.front;a[  cnt]=x;        for(register int i=head[x];i;i=edge[i].next)if(--deg[edge[i].to])q.push(edge[i].to);    }}int main(){    scanf("%d%d",&n,&m);    for(register int i=1;i<=m;  i){scanf("%d%d",&u,&v);edge[i].next=head[u];edge[i].to=v;head[u]=i;  deg[v];}    //链式前向星存边并统计入度    topsort();    for(register int i=1;i<=cnt;  i)printf("%d ",a[i]);    return 0;}

洛谷P3371 单源最短路线

关于SPFA 它死了

#include<bits/stdc  .h>int n,m,k,x,head[1000001],dis[1000001],vis[1000001],u,v,w;struct Edge{int next,to,w;}edge[1000001];inline void spfa{    for(register int i=1;i<=n;  i)dis[i]=0x7fffffff,vis[i]=0;    std::queue<int>q;q.push;dis[k]=0;vis[k]=1;    while(!q.empty{        x=q.front;vis[x]=0;        for(register int i=head[x];i;i=edge[i].next)            if(dis[edge[i].to]>dis[x] edge[i].w){                dis[edge[i].to]=dis[x] edge[i].w;                if(!vis[edge[i].to])vis[edge[i].to]=1,q.push(edge[i].to);            }    }}int main(){    scanf("%d%d%d",&n,&m,&k);    for(register int i=1;i<=m;  i){scanf("%d%d%d",&u,&v,&w);edge[i].next=head[u];edge[i].to=v;edge[i].w=w;head[u]=i;}    spfa;    for(register int i=1;i<=n;  i)printf("%d ",dis[i]);    return 0;}

  [1]容器类型:

STL初探

容器是STL中很关键的一种数据结构。常见的器皿包蕴

  • vector容器
  • deque双端数组
  • stack栈模型
  • queue队列模型
  • list链表模型
  • priotriy_queue优先级队列
  • set与multiset容器
  • map与multimap容器

除此之外容器,STL还包裹了精锐的算法,能够达成查找、删除、替换、删除等相当多广阔操作。前边会珍视疏解。

别的,迭代器也是STL首要的一环,通过迭代器,大家得以很方便对容器中的成分举办遍历,以及操作容器。后边大家会穿插解说迭代器。

4.deque

双端队列deque==vector queue,即能便捷从队列两端实行操作的行列,包蕴全体vector援救的操作,还帮忙:

#include<deque>deque<int>dq;dq.push_front//从队首插入,Odq.pop_front()//队首出队,O

有了vector和queue,为何还要deque呢?

因为有单调栈将在有单调队列啦(雾

双端队列能够支撑单调队列的操作

例题:洛谷 P1886 滑动窗口

用五个双端队列维护区间最值

#include<bits/stdc  .h>int x,n,m,cnt=1,k;std::deque<std::pair<int,int> >q,q1;//q维护单调递减序列,q1维护单调递增序列int ans[2][1000001];int main(){    scanf("%d%d",&n,&k);    for(int i=1;i<=n;i  ){        scanf("%d",&x);        while(!q.empty()&&x>=q.backq.pop_back();//保持单调性        while(!q1.empty()&&x<=q1.backq1.pop_back();        q.push_back(std::make_pair;q1.push_back(std::make_pair;        while(i-k>=q.frontq.pop_front();//保证序列在区间内        while(i-k>=q1.frontq1.pop_front();        ifans[0][cnt]=q.front().second,ans[1][cnt  ]=q1.front().second;    }    for(int i=1;i<cnt;i  )printf("%d ",ans[1][i]);    puts("");    for(int i=1;i<cnt;i  )printf("%d ",ans[0][i]);    return 0;}

单调栈和清淡队列都以挖潜标题中的单调性,及时裁撤不也许,能维持类别的可观有效性和秩序性,能化解一部分高端数据结构工夫一蹴即至的难点,值得大家寻思

注意,deque和vector相比较一般,最佳减少常数,没有氟气,慎用deque

因为NOIP所以不讲单调队列优化多重背包

    1)array:数组。

STL中的string

string是STL的字符串类型,在C语言中,我们日常用char *或者char[]字符数组来代表字符串。C 的string和C语言的char *有怎么样界别吗?

  • string是七个类,char *是指向字符的指针
  • string封装了char *,管理那些字符串,是三个char *类型的器皿
  • string永不怀想内部存款和储蓄器释放和数组越界
  • string提供了一部分列的字符串操作函数

5.pair

那便是地点代码中冒出的pair(没什么好讲的

二元组,尖括号内为本身定义的花色,用.first()访谈第一元,用.second()采访第二元,重载了<,第一元优先级高于第二元

重大用来STL别的容器的蕴藏类型,如上边程序中双端队列的品种为贰个二元组,第一元表示序号,第二元表示大小

    2)bitset:二进制位操作。

string的构造函数

既然string是一个类,那么也就有构造函数,我们商讨下string的构造函数。

#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {

    //通过const char * 初始化
    string s1 = "aaaa";

    //构造函数初始化
    string s2("bbbbb");

    //通过拷贝构造函数来初始化对象s3
    string s3 = s2;

    //用10个'a'字符来初始化字符串
    string s4(10, 'a');

    return 0;
}

6.priority_queue

优先队列,通俗讲正是没素质,插队

操作:

#include<queue>priority_queue<int>q;//定义大根堆,即大的插队priority_queue<int,vector<int>,greater<int> >q;//定义小根堆,即小的插队q.push//将x插入堆,Oq.pop()//堆顶出堆,Oq.top()//返回堆顶,O

看完下面的操作,你想到了何等呢?对,没有错,它能动态维护系列的最值

堆能优化贪心,dijkstra,prim等算法

但必要留心优先队列存款和储蓄类型必得重载<。优先队列不扶助erase,那让大家很蛋疼,施工方案为在剔除时,在堆外记录(譬如记录成分最新值),用于鉴定识别过时成分,在堆顶抽取最值时,再检查是否老式的,纵然,取下一个

例题1:洛谷 P1090 合併果子

思路正是历次抽取七个非常小值合併,用堆维护

#include<bits/stdc  .h>int n,x,ans,a,b;std::priority_queue<int,std::vector<int>,std::greater<int> >q;int main(){    scanf("%d",&n);    for(int i=1;i<=n;i  )scanf("%d",&x),q.push;    while>=2)a=q.top,b=q.top,ans =a b,q.push;    printf("%dn",ans);    return 0;}

这正是堆优化贪心

例题2:洛谷P4779 单源最短路径

堆优化dijkstra

#include<bits/stdc  .h>int x,y,n,m,k,u,v,w,head[1000001],dis[1000001],vis[1000001];struct Edge{int next,to,w;}edge[1000001];inline void dijkstra{    for(register int i=1;i<=n;  i)dis[i]=0x7fffffff,vis[i]=0;//初始化    std::priority_queue<std::pair<int,int>,std::vector<std::pair<int,int> >,std::greater<std::pair<int,int> > >q;q.push(std::make_pair;dis[k]=0;    while(!q.empty{        x=q.top().second;q.pop();        ifcontinue;        vis[x]=1;        for(register int i=head[x];i;i=edge[i].next)if(dis[edge[i].to]>dis[x] edge[i].w)dis[edge[i].to]=dis[x] edge[i].w,q.push(std::make_pair(dis[edge[i].to],edge[i].to));    }}int main(){    scanf("%d%d%d",&n,&m,&k);    for(register int i=1;i<=m;  i)scanf("%d%d%d",&u,&v,&w),edge[i].next=head[u],edge[i].to=v,edge[i].w=w,head[u]=i;    dijkstra;    for(register int i=1;i<=n;  i)printf("%d ",dis[i]);    return 0;}

毒瘤压行

那就是堆优化dijkstra,Ologn)比有些死了的算法好些个了

    3)deque:双向队列。

字符串的遍历

字符串的遍历,有三种遍历的办法

  • 数组形式遍历,通过[]操作符遍历 (不会抛出分外)
  • at()方法遍历,依据index取值 (会抛出卓殊)
  • 透过STL迭代器遍历
int main(int argc, const char * argv[]) {

    //创建字符串对象
    string str("abcdefg");

    //数组形式遍历
    for (int i = 0; i < str.length(); i  ) {
        cout<< str[i] << endl;
    }

    //at方法遍历
    for (int i = 0; i < str.length(); i  ) {
        cout << str.at(i) << endl;
    }

    //迭代器遍历
    for (string::iterator it = str.begin(); it != str.end(); it  ) {
        cout << *it << endl;
    }

    return 0;
}

数组格局和at方法格局,有四个众人周知的不等

  • 数组格局,如若出现越界也许别的错误,不会抛出极其,程序直接终端。
  • at()方法遍历,出现越界或其余错误,会抛出极其,程序可以管理非常。

迭代器其实能够当作是三个字符的指针,上个例子中string::iterator it = str.begin()便是概念二个string类型的迭代器,指向str的率先次地方。*it就象征方今的字符。注意str.end()意味着字符串最终贰个字符的后边八个职位。要是it == str.end()就意味着已经遍历到终点了。

7.string

字符串string,很几个人不是很会利用它,其实它能在水掉很多字符串的题

基本操作:

#include<string>#include<sstream>//stringstream头文件string s,s1;stringstream ss;ss>>s;char c;cin>>s//输入[], , =,>,<,>=,<=,==,!=,= //重载[],从0开始编号, 连接两个字符串,比较运算符从第一个字符开始比较,=赋值getline//输入一行s.push_back//字符串尾端加入字符cs.append//字符串尾端加入字符cs.append//在字符串尾端加入n个字符cs.insert//在迭代器it处插入cs.substr//返回l到r的字符串s.find//搜索字符串,返回第一次找到的位置,若没找到返回-1s.empty()//是否为空,为空返回1,否则返回0s.erase//清除迭代器it指向的元素s.erase//清除迭代器it1到it2之间的元素s.replace(a,len,str)//从a开始len个用str替换

常用操作正是这么些了,find在必然水平上能够取代KMP, 和substr能够组织字符串只要不是模板题或数据卡你,固然时间复杂度是错的,也能在你不会写时骗到越来越多的分,且调节和测量检验难度十分低,纯模仿至少能得到分,只要您坚信,n^2过百万,暴力碾标算,依照常数的理想以及NOIP的水数据就有希望赢得AC的好战表

你一定会好奇stringstream是怎样,让我来告诉你

试想一道题因为找不到这样的题,输入若干个整数,求和

倘使你会快读,应该能写出来,可是轻易写错,也可能有一些难知晓,这里提供一种缓和方案,使用stringstream,很轻便驾驭

#include<bits/stdc  .h>string s;int sum,x;int main(){    getline(std::cin,s);    stringstream ss;    while(ss>>x)sum =x;    printf("%d",sum);    return 0;}

今昔清楚stringstream了呢,它能将读入的字符串形成任何类型的变量,或一行字符串造成空格分隔的八个字符串。但请稳重,string相当的慢,stringstream更加慢,所以依然那句话,未有氯气,慎用

综上,有效地行使各类字符串管理函数和效仿,能使您的NOIP分数进步三个水平

    4)forward_list:单向链表。

string与char *的转换

string提供了成员函数c_str来将string对象转化成const char *。string提供了copy(buf,size,begin)成员函数来说string从begin职位上马的size个字符拷贝到buf中。供给潜心的是:

  • 要是buf容纳不下,会越界
  • 拷贝过去后,不会扭转成C风格的字符串,也正是不会在buf前边加多'\0'
int main(int argc, const char * argv[]) {

    //1 string转char *
    string str("aaaaaa");
    const char *p = str.c_str();

    //2 char *转string
    const char *p1 = "12345";
    string str2 = p1;

    //3 string拷贝到buf[]中
    char buf[128] = {0};
    //从0开始,拷贝3个字符到buf指向的内存空间
    //如果buf空间容纳不下,会越界
    //拷贝过去时,不会给buf末尾添加\0
    str.copy(buf, 3, 0);

    return 0;
}

8.set和multiset

聚焦和可重集结,内部贯彻是一棵红黑树呵呵,不过常数异常的大使得它的频率非常低

基本操作:

#include<set>set<int>a;multiset<int>b;a.size//返回大小,Oa.empty()//返回是否为空,空返回1,否则返回0a.clear()//清空,Oa.begin()//返回最小元素迭代器a.end()//返回最大元素迭代器a.insert//插入xa.find//查找x,若存在返回指向该元素的迭代器,若不存在返回a.enda.lower_bound//返回第一个大于等于x的元素的迭代器,Oa.upper_bound//返回第一个大于x的元素的迭代器,Oa.erase//删除迭代器it指向的元素,Oa.erase//删除所有等于x的元素,O,k为等于x的元素个数if((it=s.find!=s.ends.erase;//可以只删除一个等于x的元素a.count//返回元素个数,O,k为等于x的元素个数

set能排序并去重,能造福地张开离散化等操作,还是能用它完结珂朵莉树。但只顾,set,multiset和map的迭代器的只扶助自增或自减且自增或自减的时刻复杂度是O的,所以在利用时断定要留神

例题1:洛谷 UVA10815 Andy's First Dictionary

鉴于string重载了<,所以把非字母字符转化为空格,再用stringstream得到单词丢进set,排序且去重

#include<bits/stdc  .h>std::set<std::string>zd;std::string s,dc;int main(){    while(std::cin>>s){        for(register int i=0;i<s.size            if(s[i]>='a'&&s[i]<='z'||s[i]>='A'&&s[i]<='Z')s[i]=tolower;            else s[i]=' ';        std::stringstream ss;        while(ss>>dc)zd.insert;    }    for(std::set<std::string>::iterator it=zd.begin();it!=zd.endstd::cout<<*it<<std::endl;    return 0;}

从上面包车型客车例题就能看出set排序加去重的方便人民群众了

例题2:洛谷 UVA136 Ugly Numbers

用事先队列保存全体已成形的丑数,每一遍取最小x,生成2x,3x,5x插入堆中,注意多个丑数有多样生成方式,所以能够用set判定是不是已生成过

#include<bits/stdc  .h>std::priority_queue<long long,std::vector<long long>,std::greater<long long> >q;std::set<long long>s;long long a[3]={2,3,5},x,t;int main(){    q.push;s.insert;    for(register int i=1;;  i){        x=q.top;        if{printf("The 1500'th ugly number is %d.n",x);break;}        for(register int j=0;j<3;  j){            t=x*a[j];            if(!s.counts.insert,q.push;        }    }    return 0;}

从上得以看到学会何况利用多少个容器,一举三反,能化解更加多的标题。

    5)list:双向链表。

string的拼接

string为大家提供了三种字符串拼接格局,一种是重写了 操作符,大家得以一贯将连个字符串相加,类似于java的语法。另一种是string提供了成员函数append()供大家拼延续个字符串.

int main(int argc, const char * argv[]) {

    string s1 = "123456";
    string s2 = "abcdef";

    //直接使用加号运算符拼接
    string s3 = s1   s2;

    //使用成员函数拼接
    string s4 = s1.append(s2);

    cout<<s3<<endl;
    cout<<s4<<endl;

    return 0;
}

9.map

map映射,它的里边贯彻也是一棵红黑树呵呵,同样,也因为常数极大使得成效异常的低

基本操作

#include<map>map<key,value>a;//建立一个key到value的映射,如map<string,int>aa.size()//返回大小,Oa.empty()//返回是否为空,空返回1,否则返回0,Oa.clear()//清空,Oa.begin()//返回第一个元素的迭代器,O//返回最后一个元素的迭代器,Oa.insert(pair<string,int>)//参数必须是pair,Oa.erase(pair<string,int>)//参数必须是pair或迭代器,Oa.erase//Oa.find//查找x,若存在返回指向key为x的二元组的迭代器,Oa[x]//重载了[],O,需要注意,若x不存在,则会自动新建一个二元组,强烈建议用[]之前,先用find()检查存在性

map可充足,它能够一定水准上代表hash表

例题1:洛谷 P3370 字符串哈希

用map不光能缓慢解决这道题,还能够总结单词的产出次数

#include<bits/stdc  .h>std::map<std::string,int>a;int n;std::string s;int main(){    scanf("%d",&n);    while{        std::cin>>s;        if==a.end  a[s];//统计单词的出现次数    }    printf("%d",a.size;    return 0;}

能够方便的代表hash表,但常数大,有的时候要求专心

例题2:洛谷 UVA156 Ananagrams

把各类单词初步化,全体转化成小写在排序,然后丢进map总结

#include<bits/stdc  .h>std::map<std::string,int>mp;std::vector<std::string>a;std::string s;int n;inline std::string init(const std::string &s){//初始化    std::string ans=s;    for(register int i=0;i<ans.sizeans[i]=tolower;    sort(ans.begin(),ans.end;    return ans;}int main(){    while(std::cin>>s&&s[0]!='#'){        a.push_back;std::string s1=init;        if(!mp.countmp[s1]=0;        mp[s1]  ;    }    std::vector<std::string>ans;    for(register int i=0;i<a.sizeif(mp[init]==1)ans.push_back;    sort(ans.begin(),ans.end;    for(register int i=0;i<ans.sizestd::cout<<ans[i]<<std::endl;    return 0;}

此例表达,未有能够的代码设计,是无计可施发挥STL的威力的,如果未有想到先河化,很难用map简化代码

    6)map(multimap):map:键值非重复容器,multimap:键值可再次容器。 

string的追寻和替换

string类提供了find函数,用来查找字符串中内定的字符。提供了replace函数,用来替换字符串中钦命位置的字符串。

replace函数是,先删除内定地方,钦命长度的字符,然后在当前点名地点插入新的字符。

int main(int argc, const char * argv[]) {


    string s1 = "hello hello hello hello hello hello 1234 7876";

    //从0位置开始查找第一个hello出现的首位位置
    size_t index1 = s1.find("hello",0);
    cout << index1 << endl;

    //查找第一个hello出现时的首位位置
    size_t index2 = s1.find_first_of("hello");
    cout << index2 << endl;

    //查找最后一个hello出现时的末尾位置
    size_t index3 = s1.find_last_of("hello");
    cout << index3 << endl;

    //求hello出现的次数,以及对应的下标
    int count = 0;
    size_t offindex = s1.find("hello",0);
    while (offindex != string::npos) {  //如果 offindex != -1
        //找到了
        cout << "索引:" << offindex <<endl;
        count  ;
        offindex  ;
        offindex = s1.find("hello", offindex);
    }

    //把hello替换成welcome
    size_t offindex1 = s1.find("hello", 0);
    while (offindex1 != string::npos) {

        //从offindex1的位置开始删除5个位置,并插入新的字符串welcome
        s1.replace(offindex1, strlen("hello"), "welcome");

        //从后面的位置开始
        offindex1  = strlen("welcome");

        //继续查找
        offindex1 = s1.find("hello", offindex1);
    }
    cout << "替换后的字符串:" << s1 <<endl;

    return 0;
}

10.bitset

bitset可看作多位二进制数,每8位占用四个字节,相当于状压的bool数组,支持大旨位运算,n位bitset推行三次位运算的复杂度可身为n/32,成效较高

#include<bitset>bitset<1000001>s;//尖括号中写位数~s//按位取反&,|,^//按位与或,异或<<,>> //左移右移==,!= //比较是否相等s[k]//表示第k位,从0开始s.count()//返回多少位为1,O//若所有位为0返回0,否则返回1s.none()//若所有位为0返回1,否则返回0s.set()//所有位变为1s.set//把第k位变为v,即s[k]=vs.reset()//把所有位变为0,s.reset//把第k为变为0,即s[k]=0s.flip()//把所有位取反,即s=~ss.flip//把第k位取反,即s[k]^=1

例题

    7)set(multiset):自动排序非重复集合。

string区间删除和插入

string提供了inserterase个别达成插入和删除操作。

布署:pos地方插入字符串s,重返新的string。

  • string &insert(int pos, const char *s)
  • string &insert(int pos, const string &s)

插入:pos地点插入n个字符c,再次来到string。

  • string &insert(int pos, int n, char c)

删去:删除从pos地点上马的n个字符,再次来到新的string

  • string &erase(int pos, int n)

除去:删除钦赐迭代器的地方,重返当前迭代器地点

  • string::iterator erase(string::iterator it)

剔除:删除迭代器之间的字符,左闭右开区间

  • string::iterator erase(string::iterator beginIt, string::iterator endIt)
int main(int argc, const char * argv[]) {

    string s1 = "hello1 world!";

    //1 删除字符串中的'1'
    //---通过find函数,查找'1'所在的迭代器位置
    string::iterator it = find(s1.begin(), s1.end(), '1');
    //---删除
    if (it != s1.end()) {
        s1.erase(it);
    }
    cout << s1 << endl;

    //2 删除起始迭代器位置的字符
    s1.erase(s1.begin(), s1.begin()   3);
    cout << s1 << endl;

    //3 在0位置插入"AAA"
    s1.insert(0, "AAA");
    cout << s1 << endl;

    return 0;
}

11.algorithm

STL的算法库,提供了

int a[1000001];reverse(a 1,a n 1);//翻转1~nint m=unique(a 1,a n 1)-a-1;//m为去重后的元素个数random_shuffle(a 1,a n 1);//随机打乱do{}next_permutation(a 1,a n 1);//下一个排列,当不存在排名更靠后的排列返回0,否则返回1sort(a 1,a n 1);//快排inline void cmp(const int &a,const int &b){return ...}sort(a 1,a n 1,cmp)//cmp自定义快排,返回值为1即交换lower_bound(a 1,a n 1,x)//返回第一个大于等于x的元素下标upper_bound(a 1,a n 1,x)//返回第一个大于x的元素下标

上述就是STL库中的常用的函数,在那之中a数组可用vector,deque,string等容器替换

最后,祝大家NOIP2018 rp

    8)vector:动态数组。

string算法相关

当下广大的string的算法是高低写转换。一般选拔函数transform来开展转移。

int main(int argc, const char * argv[]) {

    string s1 = "abcdefg";
    string s2 = "AEDLFLKJDLKJFL";

    //小写全部转换成大写,转换的结果放在s1.begin()的位置,后面的操作需要强制转换成指定的函数类型
    transform(s1.begin(), s1.end(), s1.begin(), (int (*)(int))toupper);
    cout << s1 <<endl;

    //大写全部转换成小写
    transform(s2.begin(), s2.end(), s2.begin(), (int (*)(int))tolower);
    cout << s2 <<endl;

    return 0;
}

    9)unordered_set(unordered_multiset):依照hash来囤积的set(multiset)。

STL中的vector容器

vector是将元素放到动态数组中加以管理的器皿。vector容器能够随机存取成分,也正是说协助[]运算符和at办法存取。

  • vector在后面部分增多或然移除成分非常的慢,在个中操作拾贰分耗费时间,因为它需求活动元素

    10)unordered_map(unordered_multimap):依照hash来积累的map(multiset)。

vector的主干用法

既是vector是容器,那么就能够向这一个容器增添删减成分。

大旨用法:

  • front()重临底部成分的援引,能够当左值
  • back()回去尾部成分的引用,能够当左值
  • push_back()添新币素,只好后面部分增多
  • pop_back()移除成分,只好在尾巴部分移除
int main(int argc, const char * argv[]) {

    //定义一个vector容器
    vector<int> v1;

    //插入元素(尾部插入)
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);

    //迭代器遍历打印
    for (vector<int>::iterator it = v1.begin(); it != v1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    //修改头部元素的值(front()返回是引用,可以当左值)
    v1.front() = 44;

    //输出头部元素
    cout<< "头部元素:" << v1.front() << endl;

    //修改尾部的值(back()返回是引用,可以当左值)
    v1.back() = 99;

    //输出尾部元素
    cout << "尾部元素" << v1.back() <<endl;

    //删除元素(从尾部删除)
    v1.pop_back();

    //迭代器遍历打印
    for (vector<int>::iterator it = v1.begin(); it != v1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

  [2]容器的分类:

vector的初步化

vector有4种艺术开首化,有直接起先化,也要因此拷贝构造函数开端化。

int main(int argc, const char * argv[]) {

    //直接构造函数初始化
    vector<int> v1;
    v1.push_back(1);
    v1.push_back(2);
    v1.push_back(3);
    v1.push_back(4);

    //通过拷贝构造函数初始化
    vector<int> v2 = v1;

    //使用部分元素来构造
    vector<int> v3(v1.begin(), v1.begin()   1);
    vector<int> v4(v1.begin(), v1.end());

    //存放三个元素,每个元素都是9
    vector<int> v5(3,9);

    return 0;
}

    1)容器分为顺序容器和涉嫌容器。

vector的遍历

vector的遍历有八种主意,能够依据[]照旧迭代器遍历。

内需重视的是:

  • []措施,如若越界或出现别的错误,不会抛出特别,大概会崩溃,也许数量随机出现
  • at主意,若是越界或出现任何错误,会抛出格外,须要捕获十分并拍卖
  • 迭代器提供了逆向遍历,能够经过迭代器来贯彻逆向遍历,当然下边两种艺术也足以
int main(int argc, const char * argv[]) {

    //创建vector
    vector<int> v1;

    //插入元素
    for (int i = 0; i < 10; i  ) {
        v1.push_back(i);
    }

    //遍历-[]取值
    for (int i = 0; i < v1.size(); i  ) {
        cout << v1[i] << " ";
    }
    cout << endl;

    //遍历-at取值
    for (int i = 0; i < v1.size(); i  ) {
        cout << v1.at(i) << " ";
    }
    cout << endl;

    //遍历-迭代器遍历
    for (vector<int>::iterator it = v1.begin(); it != v1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    //遍历-迭代器逆向遍历
    for (vector<int>::reverse_iterator it = v1.rbegin(); it != v1.rend(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    //测试越界
    cout << "[]越界:" << v1[20] << endl;      //不会抛出异常,可能会崩溃,可能会乱码
    cout << "at越界:" << v1.at(20) << endl;   //会抛出异常,需要捕获异常

    return 0;
}

    2)顺序容器是不进行自动排序的,关联容器是根据成分的值举行活动排序的。在那之中map和set是关系容器,别的的是各种容器,最要紧的正是涉嫌容器有find方法,能够便捷搜索成分。

vector的push_back强化

push_back是在现阶段vector的内部存款和储蓄器末尾拷贝成分步入容器。注意那个地方大概产生浅拷贝,所以容器中的对象要扶助拷贝操作。另外,假若vector开头化了个数,而不开始化具体的值,push_back也只会在最后面追加。

int main(int argc, const char * argv[]) {

    //初始化10个元素的容器
    vector<int> v(10);

    //打印容器大小
    cout << v.size() << endl;

    //push_back添加元素
    v.push_back(100);

    //打印容器大小
    cout << v.size() << endl;

    //遍历后的结果是  0 0 0 0 0 0 0 0 0 0 100
    for (vector<int>::iterator it = v.begin(); it != v.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

  [3]依次容器的使用验证:

vector的元素删除

vector的删减,是基于任务张开删减,假如想要删除某些成分,须求找到当前成分的迭代器地点,再扩充删减。

erase(iterator)函数,删除后会重回当前迭代器的下叁个岗位。

int main(int argc, const char * argv[]) {

    //1 创建容器并初始化
    vector<int> v1(10);
    for (int i = 0; i < v1.size(); i  ) {
        v1[i] = i;
    }

    //2 区间删除
    //--2.1 删除前3个元素
    v1.erase(v1.begin(), v1.begin()   3);

    //--2.2 删除指定位置的元素
    v1.erase(v1.begin()  3);

    //3 根据元素的值进行删除,删除值为2的元素
    v1.push_back(2);
    v1.push_back(2);
    vector<int>::iterator it = v1.begin();
    while (it != v1.end()) {
        if (*it == 2) {
            it = v1.erase(it);   //删除后,迭代器指针会执行下一个位置并返回。
        }else{
            it  ;
        }
    }

    //4 遍历打印
    for (vector<int>::iterator it = v1.begin(); it != v1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

    1)除了array是原则性大小外,别的容器都提供自动内存管理。

vector的插入成分

vector提供了insert函数,结合迭代器位置插入内定的要素。

假若迭代器地方越界,会抛出非常。

int main(int argc, const char * argv[]) {

    //初始化vector对象
    vector<int> v1(10);

    //在指定的位置插入元素10的拷贝
    v1.insert(v1.begin()   3, 10);

    //在指定的位置插入3个元素11的拷贝
    v1.insert(v1.begin(), 3, 11);

    //遍历
    for (vector<int>::iterator it = v1.begin(); it != v1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

    2)string和vector保存在一连内存中,由此随机寻访相当慢,不过在中间插入删除会非常的慢。

STL中的deque容器

deque是一个双端数组容器:能够在头顶和尾巴操作成分。

  • push_back 从尾部插入成分
  • push_front 从头顶插入元素
  • pop_back 从尾巴部分删除元素
  • pop_front 从头顶删除成分

知识点:

distance函数可以求出当前的迭代器指针it距离尾部的地点,也正是容器的指针

用法: distance(v1.begin(), it)

int main(int argc, const char * argv[]) {

    //定义deque对象
    deque<int> d1;

    //尾部插入元素
    d1.push_back(10);
    d1.push_back(20);
    d1.push_back(30);

    //头部插入元素
    d1.push_front(1);
    d1.push_front(2);
    d1.push_front(3);

    //尾部删除元素
    d1.pop_back();

    //头部删除元素
    d1.pop_front();

    //修改头部和尾部的值
    d1.front() = 111;
    d1.back()  = 222;

    //查找元素为1的下标
    //通过distance求取下标
    deque<int>::iterator it = d1.begin();
    while (it != d1.end()) {
        if (*it == 1) {
            cout << "下标:" << distance(d1.begin(), it) << endl;
        }
        it  ;
    }

    //遍历
    for (deque<int>::iterator it = d1.begin(); it != d1.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

    3)deque随机访问异常的快,何况在两岸插入删除非常的慢,可是在中间插入删除会极慢。

STL中的stack栈容器

在数据结构中,栈是一种先入后出的器皿,增台币素叫压栈或许入栈。移除成分平常堪当出栈。

STL提供的stack容器,也是这种基本项目。这里大家演示一下着力成分类型和复杂性因素类型。

▽ 基础数据类型的stack

int main(int argc, const char * argv[]) {

    //定义stack对象
    stack<int> s1;

    //入栈
    s1.push(1);
    s1.push(2);
    s1.push(3);
    s1.push(4);

    //打印栈顶元素,并出栈
    while (!s1.empty()) {
        //取出栈顶元素
        cout << "当前栈顶元素" << s1.top() << endl;

        //获取栈的大小
        cout << "当前栈的大小" << s1.size() << endl;

        //出栈
        s1.pop();
    }

    return 0;
}

▽ 复杂数据类型的stack

//定义类
class Teacher {

public:

    char name[32];
    int  age;

    void printT()
    {
        cout << "age = " << age << endl;
    }

};

int main(int argc, const char * argv[]) {

    Teacher t1, t2, t3;
    t1.age = 22;
    t2.age = 33;
    t3.age = 44;

    //定义栈容器
    stack<Teacher> s1;

    //入栈
    s1.push(t1);
    s1.push(t2);
    s1.push(t3);

    //出栈并打印
    while (!s1.empty()) {
        //打印栈顶元素
        Teacher tmp = s1.top();
        tmp.printT();

        //出栈
        s1.pop();
    }

    return 0;
}

    4)list和forward_list在别的地点插入删除不慢,随机拜谒相当的慢。

STL中的queue队列容器

队列是一种数据结构,具备队头和队尾。常见的有FIFO(先入先出)队列等。

#include <queue>

void main()
{
    queue<int> q;
    q.push(1);
    q.push(2);
    q.push(3);

    cout << "对头元素" << q.front() <<endl;
    cout << "队列的大小 " << q.size() <<endl;

    while (!q.empty())�{

        int tmp = q.front();
        cout << tmp << " ";
        q.pop();
    }
}



class Teacher
{
public:
    int age;
    char name[32];

    void printT()
    {
        cout << "age :" << age <<endl;
    }
}

void main()
{
    Teacher t1,t2,t3;
    t1.age = 31;
    t2.age = 32;
    t3.age = 33;

    queue<Teacher > q;
    q.push(t1);
    q.push(t2);
    q.push(t3);

    while (!q.empty())�{

        Teacher tmp = q.front();
        tmp.printT();
        q.pop();
    }

}

  [4]论及容器的采纳验证:

STL中的list容器

list容器材备如下特征:

  • 能够在头顶和尾巴插入和删除成分
  • 不能够随随意便探问成分,也便是迭代器只好只可以 ,不可能一遍性跳转

    1)map的采纳,map是三个键值对,其中值是二个pair对象:

list的基本操作

int main(int argc, const char * argv[]) {

    //创建list对象
    list<int> l;

    //尾部添加元素
    for (int i = 0; i < 10; i  ) {
        l.push_back(i);
    }

    //头部添加元素
    l.push_front(111);

    //遍历
    for (list<int>::iterator it = l.begin(); it != l.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    //list不能随机访问
    list<int>::iterator it = l.begin();
    it  ;
    it  ;
    cout << *it <<endl;
//    it = it   1;  //编译报错,不能随机访问
//    it = it   5;  //编译报错,不能随机访问


    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>

using namespace std;

class ca
{
public:
    int ip;
};

class comp{
public:
    bool operator()(const ca &a, const ca &b) 
    {
        return a.ip < b.ip;
    }
};

bool operator<(const ca &a, const ca &b)
{
    return a.ip < b.ip;
}

int main()
{
    //map的第三个参数,另外第三个参数使用普通函数时编译不过不知怎么回事
    ca a1, a2, a3;
    map<ca, string> addr2;            //使用全局的<运算符重载函数
    map<ca, string, comp> addr1;    //使用仿函数

    addr1.insert(pair<ca, string>(a1, "1 addr a1"));
    addr2.insert(pair<ca, string>(a1, "2 addr a1"));


    //pair的使用
    pair<ca, string> p1(a1, "1 addr a1");              //创建一个pair对象
    addr1.insert(p1);
    addr1.insert(pair<ca, string>(a2, "1 addr a2"));   //隐式的创建一个pair对象,这个是常用的方式,因为通常没有一个现成的对象
    addr1.insert(make_pair(a2, "1 addr a3"));          //调用make_pair创建一个pair对象


    //关联容器定义的类型
    /*
        map的元素类型是一个pair对象,这个很重要。
        元素:      map的元素就是map容器里面的一个值。就像是set<int>的每个元素是一个int型对象。
        关键字: map的关键字是pair对象的第一个元素。
    */
    map<ca, string>::key_type     v1;     //v1的类型是类ca,代表关键字的类型
    map<ca, string>::mapped_type  v2;     //v2的类型是string,代表关键字关联的类型
    map<ca, string>::value_type   v3;     //v3的类型是pair<ca, string>,代表值的类型

    set<string>::key_type    v4;          //v4和v5的类型是string,set的键值类型是一样的
    set<string>::value_type  v5;        
    return 0;
}

list的删除

list提供了四个函数用来删除成分,分别是eraseremove

  • erase是因而岗位依旧区间来删除,首要结合迭代器指针来操作
  • remove是透过值来删除
int main(int argc, const char * argv[]) {

    //创建list对象
    list<int> l;

    //添加数据
    for (int i = 0; i < 10; i  ) {
        l.push_back(i);
    }
    l.push_back(100);
    l.push_back(100);

    //删除头部元素
    l.erase(l.begin());

    //删除某个区间
    list<int>::iterator it = l.begin();
    it  ;
    it  ;
    it  ;
    l.erase(l.begin(), it);

    //移除值为100的所有元素
    l.remove(100);

    //遍历
    for (list<int>::iterator it = l.begin(); it != l.end(); it  ) {
        cout << *it << " ";
    }
    cout << endl;

    return 0;
}

    2)关键字类型必需定义成分的对比艺术,这一个是自然的,不然不能实行排序。实际编制程序中,假诺五个类定义了<运算符,就足以当作根本字了,那个意思就是说主要字不供给达成>和=运算符,完毕了和不实现效果与利益是同样的。还也许有正是定义<运算符要符合严苛弱序的条条框框,那意味正是自定义的<运算符函数,实现要合理,比方传给那函数三个(a,b),重返true,传给三个(b,a),还是回到true,那就不相符严厉弱序了。固然不符合不过不会变成编写翻译错误,只是用的时候会产生各样错误,举例set插入了平等的因素。

STL中的priority_queue优先级队列容器

事先级队列分为:最小值优先队列和最大值优先队列。

那边的最大值、最小值是指队头的要素(增序、降序)。暗中同意,是创办最大值优先级队列。

概念优先级的章程:

  • priority_queue<int>默断定义int类型的最大值队列
  • priority_queue<int, vector<int>, less<int>>定义int型的最大值优先队列
  • priority_queue<int, vector<int>, greater<int>>定义int型的相当小值队列

地点的概念中,lessgreater也正是谓词,是预定义好的排序函数,我们誉为“仿函数”。后边会介绍它的用法。

void main()
{
    //定义优先级队列(默认是最大值优先级队列)
    priority_queue<int> p1;

    //定义一个最大优先级队列
    //less是提前定义好的预定义函数 相当于谓词
    priority_queue<int, vector<int>, less<int>> p2;

    //定义一个最小值优先级队列v
    priority_queue<int, vector<int>, greater<int>> p3;

    //给默认的最大优先级队列入栈
    p1.push(33);
    p1.push(11);
    p1.push(55);
    p1.push(22);

    //打印最大优先级的对头元素
    cout<<"对头元素:"<< p1.top() <<endl;
    cout<<"队列的大小:"<< p1.size() <<endl;

    //给最小值优先级队列入栈
    p3.push(33);
    p3.push(11);
    p3.push(55);
    p3.push(22);

    //打印最小优先级队列的对头元素
    cout<<"对头元素:"<< p3.top() <<endl;
    cout<<"队列的大小:"<< p3.size() <<endl;

}

      严峻弱序准则正是:(1)假如传入(a,b)重临true,则传出(b,a)必得回到false。

STL中的set和multiset集结容器

set是三个汇集,Objective-C语言中也可能有汇集的定义。C 中的会集与OC中的集合也可能有不一样的地方。

  • C 的set容器,个中满含的要素是并世无两的,何况是有序的。
  • C 的set容器,是安份守己顺序插入的,无法在内定位置插入。
  • C 的set容器,其布局是红黑二叉树,插入数据的效能比vector快

                 (2)假设传入(a,b)再次来到true,传入(c,a)重返true,则传出(c,b)必需再次来到true。正是说a<b,c<a,则c要自愧不及b。

set成分的插入和删除

set提供了inserterase函数,用来对成分进行扦插和删除操作。

  • 基本功项目数据,如果插入的是重复的成分,则插入失利,重临值是三个pair类型
  • pair类型类似于swift语言中的元组的定义,通过其推断是不是插入成功
  • 复杂类型数据,须要通过仿函数来规定因素的一一,步向剖断是或不是是重复成分。在“自定义对象的排序”里面讲明。
void main()
{
    set<int> set1;

    //插入元素
    for (int i = 0; i<5; i  ) {
        int tmp = rand();
        set1.insert(tmp);
    }

    //重复插入元素(会插入不成功,下一节会分析如果根据返回值判断是否插入成功)
    set1.insert(100);
    set1.insert(100);
    set1.insert(100);
    set1.insert(100);

    for (set<int>::iterator it = set1.begin(); it != set1.end(); it  ) {
        cout << *it <<" ";
    }


    //删除集合
    while(!set1.empty())
    {
        //获取头部
        set<int>::iterator it = set1.begin();

        //打印头部元素
        cout << *it << endl;

        //从头部删除元素
        set1.erase(set1.begin());
    }

}
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <arpa/inet.h>

using namespace std;

class ca
{
public:
    unsigned ip;
    int port;
    ca(int ip1, int port1) {ip = ip1; port = port1;}

    //怎么定义<运算符都是可以的,看需求。
    //只是定义不同时,元素的排序顺序是不一样的。

    //如果用这种方式,则set里面的排列顺序为:
    //    1.1.1.1:80
    //    1.1.1.1:81
    //    1.1.1.2:80
    //    1.1.1.2:81
    //        
    //这意思就是用ip去比较地址,如果ip不同时再用port去比较地址,当然使用这种需求一般用的比较多,这种方让元素之间有一层优先级。
    bool operator<(const ca &other) const{
        if(ip < other.ip) 
            return true;
        else if(other.ip < ip) 
            return false;

        if(port < other.port) 
            return true;
        else if(other.port < port) 
            return false;

        return false;
    }

    //完全等同于上面的函数
    bool operator<(const ca &other) const{
        if(ip < other.ip ||(ip == other.ip && port <other.port)) 
            return true;

        return false;
    }

    //如果用这种方式,则set里面的排列顺序为:
    //    1.1.1.1:80
    //    1.1.1.2:80
    //    1.1.1.1:81
    //    1.1.1.2:81
    //这意思就是说希望用ip或port去比较地址,只要有一个小于就是小于,很明显这种方式用的少。
    bool operator<(const ca &other) const
    {
        if(ip < other.ip || port < other.port) 
            return true;

        return false;
    }

    //错误的方式,错误的函数不会导致编译错误,但是处理的时候会发生错误。例如下面这种就可以把相同的数据插入到set里面。
    //很明显已经违背了严格弱序的原则,因为a < b为true的时候同时b < a也为true。
    bool operator<(const ca &other) const{
        return true;
    }
};

int main()
{
    set<ca> v;
    set<ca>::iterator it;

    v.insert(ca(inet_addr("1.1.1.1"), 80));
    v.insert(ca(inet_addr("1.1.1.1"), 81));
    v.insert(ca(inet_addr("1.1.1.2"), 80));
    v.insert(ca(inet_addr("1.1.1.2"), 81));

    for(it=v.begin(); it!=v.end(); it  )
        printf("%s:%dn", inet_ntoa(*((struct in_addr *)&(it->ip))), it->port);

    return 0;
}

平日数据类型的排序

set容器是铁钉铁铆的聚合,暗中认可的相继是从小到大的。

制造会集的主意:

  • set<int>创制默许的从小到大的int类型的联谊
  • set<int,less<int>>创办二个从小打到大的int类型的集纳
  • set<int,greater<int>>始建三个从大到小的int类型的聚合

地点的less和greater便是仿函数,群集会依据这些仿函数的重回值是还是不是为真类进行排序。

//仿函数的原型,下面是C  提供的默认的greater的仿函数(删除了宏定义后的)
struct greater
{
    bool operator()(const int &left, const int &right) const
    {
        //如果左值>右值,为真。从大到小的排列
        return left > right;
    }
};

大家得以测量检验下,增多进set群集的因素确实是有顺的。

void main()
{
    //默认,从小到大
    set<int> set1;
    //从小到大--默认就是
    set<int, less<int>> set2;
    //从大到小
    set<int, greater<int>> set3;

    //添加元素
    for (int i = 0; i < 5; i  ) {
        int tmp = rand();
        set3.insert(tmp);
    }

    //遍历
    for (set<int>::iterator it = set3.begin(); it != set3.end(); it  ) {
        cout<< *it << " ";
    }
}

    3)set的迭代器是const的,就是说不可能由此三个set迭代器去修改贰个值,那一个也是当然的,因为set是稳步的,修改了就冬辰了,同理map的key值也是无法透过迭代器修改的,可是map的value是足以因此迭代器修改的。

自定义对象的排序

地点,大家看到了基础的数据类型的汇聚,是能够排序的。不过,若是会集里面放的是不相同平日的自定义对象,该怎么满意set有序的表征呢?

通过地方的例证,我们知晓,基础数据类型的set是平稳的第一原因是greater和less仿函数。所以,自定义对象的静止也是通过大家自定义仿函数来保管的。

仿函数,之所以叫仿函数,是因为它跟函数很像,但并非一个函数。它的结果如下,只要大家得以实现了那个仿函数,大家也得以对自定义对象进行排序。

//定义仿函数的结构体
struct FunctionName
{
    //重载了()运算符,实现两个自定义对象的比较
    bool opeartor() (Type &left, Type &right)
    {
        //左值大于右值,从大到小的顺序
        if(left > right) 
            return true;
        else
            return false;

    }
};

上边,大家自定义三个Student对象,依照年龄举行排序,将指标参加到set会集中,并张开打字与印刷。

假定仿函数实现了基于年龄举办排序,因为set是因素独一的,所以在插入对象的时候,借使年龄是重复的,则插入不进来了。

//定义student对象
class Student {
public:
    Student(const char *name, int age)
    {
        strcpy(this->name, name);
        this->age = age;
    }

public:
    char name[64];
    int  age;
};

//提供仿函数,用于自定义对象的set进行排序,要写一个仿函数,用来排序
struct FuncStudent
{
    //重载了括号操作符,用来比较大小
    bool operator() (const Student &left, const Student &right)
    {
        //如果左边比右边小,从小到大按照年龄排序
        if(left.age < right.age)
            return true;
        else
            return false;
    }

};

void main()
{
    Student s1("s1",32);
    Student s2("s2",22);
    Student s3("s3",44);
    Student s4("s4",11);
    Student s5("s5",22); 

    //创建集合,采用从小到大的排序
    set<Student, FuncStudent> set1;

    //插入数据
    set1.insert(s1);
    set1.insert(s2);
    set1.insert(s3);
    set1.insert(s4);
    //插入不进去(年龄有重复的,所以插不进去了),要通过返回值来确保是否插入成功
    set1.insert(s5);    

    //遍历
    for (set<Student>::iterator it = set1.begin(); it != set1.end(); it  ) {
        cout << it->age << "t" << it->name <<endl;
    }

}

    4)map和set的insert操作能够检查重回值,推断是或不是插入成功,举个例子元素已经存在则insert会失利,再次来到的pair类型的第3个值为false。

pair类型的重临值

pair类型,就恍如于Swift语言中的“元组”的概念,那一个项目包涵了五个数据类型,在函数再次回到的时候,可以况兼重临七个值。

小编们来看一下pair类型的定义它事实上是叁个结构体。它包含了多少个个性,firstsecond

template <class _T1, class _T2>
struct pair
{
    typedef _T1 first_type;
    typedef _T2 second_type;

    _T1 first;
    _T2 second;
}

地点的事例中,大家领会set集结中的成分是独一的,重复的要素插入会停业。假如判定是不是插入成功,大家能够透过insert函数的再次来到值来判定,它的重回值是三个pair花色。大家来看一下insert函数的原型:

pair<iterator,bool> insert(const value_type& __v)

回去的是pair<iterator, bool>连串,pair的首先个天性表示近日安排的迭代器的职责,第二个性格表示插入是不是成功的bool值。所以,大家得以经过第2个属性来剖断成分是不是插入成功。

//pair的使用判断set的insert函数的返回值
void test3()
{
    Student s1("s1",32);
    Student s2("s2",22);
    Student s3("s3",44);
    Student s4("s4",11);
    Student s5("s5",22);

    //创建集合,采用从小到大的排序
    set<Student, FuncStudent> set1;

    //插入数据,接收返回值
    pair<set<Student, FuncStudent>::iterator, bool> pair1 = set1.insert(s1);
    if (pair1.second == true) {
        cout << "插入s1成功" <<endl;
    }else{
        cout << "插入s1失败" <<endl;
    }
}

    5)lower_bound和upper_bound:这七个操作都回去二个迭代器,假如首要字在容器中,lower_bound重回的迭代器指向第五个成分,upper_bound再次来到的迭代器指向最终贰个职位的以往;假使首要字不在容器中,则lower_bound和upper_bound再次回到一样的地方,这些地方正是不影响排序的首要字的插入地点。倘若存在则只要(begin=lower_bound;begin!=upper_bound;begin ;)就足以遍历那么些首要字对应的持有因素。假设空头支票,则赶回的迭代器指向的地方是要查的机要字能够插入的岗位。

set容器数据的寻觅

set容器提供了多个函数用来搜求成分

  • iterator find(const key_type& __k) find函数查找成分为k的迭代器地方
  • iterator lower_bound(const key_type& __k) lower_bound函数查找小于等于元素k的迭代器地点
  • iterator upper_bound(const key_type& __k) upper_bound函数查找大于成分k的迭代器地点
  • pair<iterator,iterator> equal_range(const key_type& __k) equal_range函数再次来到一个pair类型,第三个属性表示大于等于k的迭代器地方,第三个是大于k的迭代器地方
void test4()
{
    set<int> set1;

    for (int i = 0; i < 10; i  ) {
        set1.insert(i 1);
    }

    //遍历
    for (set<int>::iterator it = set1.begin(); it != set1.end(); it  ) {
        cout << *it <<endl;
    }

    //查找元素是5的迭代器位置
    set<int>::iterator it0 = set1.find(5);
    cout << "it0:" << *it0 <<endl;

    //查找小于等于5的元素迭代器位置
    set<int>::iterator it1 = set1.lower_bound(5);
    cout << "it1:" << *it1 <<endl;

    //查找大于5的元素迭代器位置
    set<int>::iterator it2 = set1.upper_bound(5);
    cout << "it2:" << *it2 <<endl;

    //返回的pair第一个迭代器是>=5,另一个是>5
    pair<set<int>::iterator, set<int>::iterator> mypair = set1.equal_range(5);
    set<int>::iterator it3 = mypair.first;
    set<int>::iterator it4 = mypair.second;
    cout << "it3:" << *it3 <<endl;
    cout << "it4:" << *it4 <<endl; 
}

    6)multimap的应用(想必multiset的用法也是基本上的)例:

multiset容器

multiset容器,与set容器相似,不过multiset容器中的成分得以重复。别的,他也是全自动排序的,容器内部的值不可以小看修改,因为有各种的。

void test5()
{
    //定义multiset
    multiset<int> set1;

    //从键盘不停的接收值
    int tmp = 0;
    printf("请输入multiset集合的值:");
    scanf("%d", &tmp);
    while (tmp != 0) {
        set1.insert(tmp);
        scanf("%d", &tmp);
    }

    //迭代器遍历
    for (multiset<int>::iterator it = set1.begin(); it != set1.end(); it  ) {
        cout<< *it <<" ";
    }
    cout <<endl;

    //删除
    while (!set1.empty()) {
        multiset<int>::iterator it = set1.begin();
        cout << *it << " ";
        set1.erase(it);
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>

using namespace std;

/*
    查找mulimap关键字的方法
*/
int main()
{
    // 1.使用lower_bound和upper_bound
    multimap<int, string> m;
    multimap<int, string>::iterator begin, end;

    m.insert(pair<int, string>(1, "boy1"));
    m.insert(pair<int, string>(2, "girl1"));
    m.insert(pair<int, string>(2, "girl2"));
    m.insert(pair<int, string>(2, "girl3"));
    m.insert(pair<int, string>(5, "dog1"));
    m.insert(pair<int, string>(5, "dog2"));

    /*
        输出:
            key 2 value:girl1
            key 2 value:girl2
            key 2 value:girl3
            end value:dog1
        可见begin指向(2, "girl1"),end指向(5, "dog1")。
    */
    begin = m.lower_bound(2);
    end   = m.upper_bound(2);
    while(begin != end){
        printf("key 2 value:%sn", begin->second.c_str());
        begin  ;
    }
    printf("end value:%sn", end->second.c_str());

    /*
        输出:
            begin value:dog1
            end   value:dog1
        可见begin 和end都指向(5, "dog1"),因为此位置就是要查的关键字3应该插入的位置。
    */
    begin = m.lower_bound(3);
    end   = m.upper_bound(3);
    printf("begin value:%sn", begin->second.c_str());
    printf("end   value:%sn", end->second.c_str());

    /*
        输出:
            begin value:0x7fff4e76b578
            end   value :0x7fff4e76b578
            m.end value:0x7fff4e76b578
        可见begin 和end都指向m.end(),因为此位置就是要查的关键字10应该插入的位置。
    */
    begin = m.lower_bound(10);
    end   = m.upper_bound(10);
    printf("begin value:%pn", begin);
    printf("end   value:%pn", end);
    printf("m.end value:%pn", m.end());


    // 2.使用count方法得到个数
    int count;
    multimap<int, string>::iterator it;

    count = m.count(5);    //得到关键字5的元素个数
    it = m.find(5);     //指向关键字5的第一个元素

    /*
        输出:
            key 5 value:dog1
            key 5 value:dog2
    */
    while(count > 0){
        printf("key 5 value:%sn", it->second.c_str());
        it  ;
        count--;
    }

    // 3.使用equal_range
    pair<multimap<int, string>::iterator, multimap<int, string>::iterator> range;

    range = m.equal_range(2); //直接得到关键字2的迭代器的起始位置

    /*
        输出:
            key 2 value:girl1
            key 2 value:girl2
            key 2 value:girl3
    */
    while(range.first != range.second){
        printf("key 2 value:%sn", range.first->second.c_str());
        range.first  ;
    }

    return 0;
}

STL中的map和multimap映射容器

map和multimap是二个键值映射的器皿。map中的键值对都以独步一时的,可是multimap中一个键方可对应多个值。

  • map和multimap是关联式容器,键值成对存在
  • map和multimap是红黑变体的平衡二叉树结构
  • map只辅助唯一的键值对,集结中的成分是遵纪守法一定的顺序排列的
  • multimap中的键能够出现多次
  • map和multimap的要素插入进度是遵从顺序插入的

    7)unordered_map和unordered_set:那七个容器是无序的,正是说不是按顺序存款和储蓄的。因为map和set都以半自动排序的,譬如遍历map或set,能够获取按梯次排序的值。可是unordered_map和unordered_set是按hash存款和储蓄的,遍历会获得不按顺序输出的值,所以只要需要存款和储蓄的成分有序就用map,如若冬季並且供给连忙寻找,就用unordered_map。map和unordered_map效能对比的例子:

map成分的增删改查

map成分的插入,有两种办法:

  1. 调用insert函数插入pair类型的键值对
  2. 从来利用[]来对键举办复制,类似于Objective-C中的NSMutableDictionary赋值一样。

map的insert函数再次回到的是pair类型,pair的第3个参数表示是还是不是插入成功。固然插入的成分键名一样,则插入退步。

map成分的删除,跟上边其余的器皿一样,都是一直调用erase函数.

int main()
{
    map<int, string> map1;

    //insert方法插入
    //--1 通过pair<int, string>(1,”chenhua“) 构造pair元素
    map1.insert(pair<int, string>(1,"chenhua"));
    //--2 通过make_pair构造pair元素
    map1.insert(make_pair(2,"mengna"));
    //--3 通过value_type构造pair元素
    map1.insert(map<int, string>::value_type(3,"chenmeng"));

    //[]直接插入
    map1[4] = "menghua";

    //重复插入(插入会不成功)
    pair<map<int, string>::iterator, bool> pair1 = map1.insert(make_pair(2, "haha"));
    if (pair1.second) {
        cout << "重复插入成功" << endl;
    }else{
        cout << "重复插入失败" << endl;
    }

    //元素的修改
    //map[1] = "22"的方式,如果不存在键则插入,存在键则修改
    map1[2] = "haha";

    //元素的删除
    //--删除值为"haha"的元素
    for (map<int, string>::iterator it = map1.begin(); it != map1.end(); it  ) {
        if (it->second.compare("haha") == 0) {
            map1.erase(it);
        }
    }

    //遍历
    for (map<int, string>::iterator it = map1.begin(); it != map1.end(); it  ) {
        cout << it->first << "t" << it->second << endl;
    }

    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <set>
#include <map>
#include <arpa/inet.h>
#include <tr1/unordered_map>
using namespace std::tr1;

using namespace std;

double timeuse(struct timeval begin, struct timeval end)
{
    double res;

    if(end.tv_usec < begin.tv_usec){
        end.tv_usec  = 1000000;
        end.tv_sec--;
    }

    res = end.tv_usec - begin.tv_usec;
    res  = (end.tv_sec - begin.tv_sec)*1000000;
    return res;
}

int main()
{
    int i;

    map<int, int> m;
    map<int, int>::iterator it;
    unordered_map<int, int> um;
    unordered_map<int, int>::iterator uit;
    struct timeval tv_begin, tv_end;
    double res;

#define BEGIN   gettimeofday(&tv_begin, NULL);
#define END(s)  do{
                    gettimeofday(&tv_end, NULL); 
                    res = timeuse(tv_begin, tv_end); 
                    printf("%-30s, usetime:%f usec [%f sec]n", s, res, res/1000000);
                }while(0)

    BEGIN
    for(i=0; i<10000000; i  )
        m.insert(pair<int, int>(i, i));
    END("map insert");

    BEGIN
    for(i=0; i<10000000; i  )
        um.insert(pair<int, int>(i, i));
    END("unordered_map insert");

    BEGIN
    it = m.find(500000);
    END("map find");

    BEGIN
    uit = um.find(500000);
    END("unordered_map find");

    return 0;
}

map成分的查找

map提供了三个函数进行key的搜索:find和equal_range。

int main()
{
    //定义map
    map<int ,string> map1;
    map1[1] = "chenhua";
    map1[2] = "mengna";

    //查找key=100的键值对
    map<int, string>::iterator it = map1.find(100);
    if (it != map1.end()) {
        cout << "存在key=100的键值对";
    }else{
        cout << "不存在" << endl;
    }


    //查找key = 1000的位置
    //返回两个迭代器,第一个表示<=1000的迭代器位置,第二个是>1000的迭代器位置
    pair<map<int, string>::iterator, map<int, string>::iterator> mypair = map1.equal_range(1000);
    if (mypair.first == map1.end()) {
        cout << "大于等于5的位置不存在" << endl;
    }else{
        cout << mypair.first->first << "t" << mypair.first->second << endl;
    }

    if (mypair.second == map1.end()) {
        cout << "大于5的位置不存在" << endl;
    }else{
        cout << mypair.second->first << "t" << mypair.second->second << endl;
    }

    return 0;
}

  输出:

multimap容器

multimap容器,与map容器的独步天下不相同是:multimap协理八个键值。

由于帮忙三个键值,multimap提供了cout函数来计量同多个key的成分个数。

class Person {


public:

    string name;    //姓名
    int age;        //年龄
    string tel;     //电话
    double sal;     //工资

};

void test()
{
    Person p1,p2,p3,p4,p5;
    p1.name = "王1";
    p1.age  = 31;

    p2.name = "王2";
    p2.age  = 31;

    p3.name = "张3";
    p3.age  = 31;

    p4.name = "张4";
    p4.age  = 31;

    p5.name = "钱5";
    p5.age  = 31;


    multimap<string, Person> map2;

    //sale部门
    map2.insert(make_pair("sale", p1));
    map2.insert(make_pair("sale", p2));

    //development部门
    map2.insert(make_pair("development", p3));
    map2.insert(make_pair("development", p4));

    //Finanncial部门
    map2.insert(make_pair("Finanncial", p5));


    //遍历
    for (multimap<string, Person>::iterator it = map2.begin(); it != map2.end(); it  ) {


        cout << it->first << "t" << it->second.name << endl;

    }

    //按部门显示员工信息
    int developNum = (int) map2.count("development");
    cout << "development部门人数:" << developNum << endl;
    multimap<string,Person>::iterator it2 = map2.find("development");
    int tag = 0;
    while (it2 != map2.end() && tag < developNum) {
        cout << it2->first << "t" << it2->second.name <<endl;
        it2   ;
        tag   ;
    }

    //把age=32 修改name= 32
    for (multimap<string, Person>::iterator it = map2.begin(); it != map2.end(); it  ) {
        if (it->second.age == 32) {
            it->second.name = "32";
        }
    }
}

int main(int argc, const char * argv[]) {

    test();

    return 0;
}
map insert                    , usetime:10102899.000000 usec [10.102899 sec]
unordered_map insert          , usetime:2749505.000000 usec [2.749505 sec]
map find                      , usetime:3.000000 usec [0.000003 sec]
unordered_map find            , usetime:1.000000 usec [0.000001 sec]

STL容器的通用性钻探

到此地,STL的容器大家着力教学停止了。STL的器皿首要采取了C 的模板本性来兑现。供给细心:

  • 容器缓存了节点,节点类要确认保证支持拷贝(不然出现浅拷贝难题,导致崩溃)
  • 容器中的一般节点类,供给提供拷贝构造函数,同等对待载等号操作符(用来赋值)
  • 容器在插入成分时,会自动举办成分的正片。

本着容器,容器之间也帮衬拷贝。所以需求留神:

  • 除外queue和stack外,每一个容器都提供了可回到迭代器的函数,运用重返的跌打器就能够访谈元素
  • 万般STL不会抛出分外,供给使用者确认保障传入准确的参数
  • 各样容器都提供了三个暗中认可构造函数和一个私下认可拷贝构造函数

  由此可见unordered_map在插入和探究方面或许比map要快很多的,当然内部存款和储蓄器占用的也多。

STL容器的因素拷贝

下边,大家演示一下,假如容器成分若无完成拷贝构造函数,出现浅拷贝后的倒台难题。

#include <iostream>
#include <string>
#include <vector>
using namespace std;


class Student {

public:
    Student(const char *name, int age)
    {
        cout << "构造函数" << endl;

        //分配内存空间
        m_name = new char[strlen(name)   1];
        //值拷贝
        strcpy(m_name, name);

        m_age = age;
    }


    ~Student()
    {
        printf("%p 指向的空间 调用析构函数n", m_name);
        if (m_name != NULL) {
            delete []m_name;
            m_age = 0;
        }
    }

private:
    char *m_name;
    int   m_age;

};


int main()
{
    Student s1("chenhua",24);

    vector<Student> v1;
    v1.push_back(s1);

    return 0;
}

地方的代码段,运营后的结果如下:

构造函数
0x100302a00 指向的空间 调用析构函数
0x100302a00 指向的空间 调用析构函数

运作后,打印出结果后并报错。报错原因是同二个内部存款和储蓄器空间被放走了2次,导致的夭折。其根本原因是,v1将s1拷贝到容器,由于Student未有重写拷贝构造函数,从而出现了浅拷贝,只拷贝了地址。释放的时候鲜明出现错误。

借使大家给Student重写了拷贝构造函数和重载了等号操作符,则下边包车型客车谬误就不晤面世。

//重写拷贝构造函数
Student(const Student &obj)
{
    //分配内存空间
    m_name = new char[strlen(obj.m_name)   1];
    //值拷贝
    strcpy(m_name, obj.m_name);

    m_age = obj.m_age;
}

//重载等号运算符
Student & operator=(const Student &obj)
{
    //释放旧值
    if (m_name != NULL) {
        delete [] m_name;
        m_age = 0;
    }

    //分配内存空间并赋值
    m_name = new char[strlen(obj.m_name)   1];
    strcpy(m_name, obj.m_name);
    m_age = obj.m_age;

    return *this;
}

3.STL适配器

STL容器的相比较

STL提供了累累容器,每个容器有其自个儿的特色,大家该怎么利用它们啊?

vector deque list set mutliset map multimap
内存结构 单端数组 双端数组 双向链表 二叉树 二叉树 二叉树 二叉树
随机存取 对key而言是
查找速度 非常慢 对key而言快 对key而言快
插入删除 尾端 头尾两端 任何位置 - - - $1

  [1]stack:栈适配器。这些要细心的就是栈里面是有七个器皿来存款和储蓄成分的,常规的敞亮栈应该正是二个数组,其实不是,栈私下认可的器皿是二个双向队列(deque),栈也足以用vector、list等作为成分的器皿,有个规范便是轻巧要求提供push_back()、back()、和pop_back()方法,因为set未有提供这么些方式,所以无法把set作为栈的容器。所谓栈正是在叁个器皿上面加了一些操作函数,封装成了栈模板(STL中栈定义:template < class T, class Container = deque<T> > class stack;)。

  [2]queue:单向队列适配器。这些和stack是同一的,特点是先进先出。当然也是索要提供叁个器皿来囤积成分,默许是deque。

  [3]priority_queue :优先级队列适配器。那个适配器是把容器内的因素排序好的,每一趟能够得到优先级最高的要素。所以能够流传多少个优先级比较函数,暗许比较函数是<,默许的器皿是vector,定义格局priority_queue<Type, Container, Functional>。其实那么些适配器只是在queue上面加了一个开始时期级排序函数。

4.STL切实用法

  [1]const_iterator:若是不供给写访谈容器时,应该接纳const_iterator迭代器,方法和iterator是相同的。

  [2]reverse_iterator(const_reverse_iterator):能够从后迈入遍历容器。

  [3]管住体量:除了array之外,容器的内部存款和储蓄器都以机关管理的。size()表示近日的因素数量,capacity()表示已经预分配的容积,reserve()表示设置预分配的容积。那个意思乃是capacity()是早就预分配好的体量,不管是前后相继自动分配还是手动调用reserve()分配。还大概有正是resize()是设置容器使用的尺寸,和预分配未有涉及,举个例子当前因素个数是5,则resize(8)会往容器扩大3个要素,resize(4)会删除1个成分。

  [4]substr:拷贝原始string的一有的或任何。其余string类还提供了一部分别样艺术,来产生和char *花色的字符串的管理函数,比如周围strstr、strrstr的函数。

  举例:

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>
#include <array>

using namespace std;

int main()
{
    vector<int> v;
    vector<int>::const_iterator c_it;
    vector<int>::const_reverse_iterator cr_it;

    v.push_back(1); v.push_back(2); v.push_back(3);v.push_back(4);v.push_back(5);

    //iterator对应的是begin、end
    for(c_it = v.begin(); c_it!= v.end(); c_it  )
        printf("%dn", *c_it);

    //reverse_iterator对应的是rbegin、rend,cr_it = v.begin()是编译不过的
    for(cr_it = v.rbegin(); cr_it!= v.rend(); cr_it  )
        printf("%dn", *cr_it);

    // 容量设置
    printf("size:    %un", v.size());
    printf("capacity:%un", v.capacity());        //程序自动预分配的容量,例如值是8
    printf("--------------------------n");

    v.reserve(20);                                //手动设置预分配的容量,如果值小于已经自动预分配的容量则不生效
    printf("size:    %un", v.size());
    printf("capacity:%un", v.capacity());        //此时值就是20了
    printf("--------------------------n");

    v.resize(200);                                //强制设置元素个数是200                                 
    printf("size:    %un", v.size());            //值是200
    printf("capacity:%un", v.capacity());        //超过预分配的容量后,程序就会再次自动预分配

    //string操作
    string src("test string");
    string dst;

    // substr(pos, n)   pos默认是0,n默认是总长度,所以只传一个参数的时候其实是指定了拷贝的起始位置
    dst = src.substr(3);      
    printf("dst:%sn", dst.c_str());             // dst:"t string" 
    dst = src.substr();      
    printf("dst:%sn", dst.c_str());             // dst:"test string"

    return 0;
}

 5.C 手册

  

 

  

TAG标签:
版权声明:本文由澳门新葡8455手机版发布于计算机编程,转载请注明出处:师傅和徒弟恋大法好,你看本人就够了