STL,标准模板库,从根本上说是一些‘’容器‘’的集合,这些容器有list,vector,set,map等。STL也是一些算法和其他一些组建的集合,STL现在也是c++的一部分,因此不用安装额外的库文件。
在c++标准中,STL被组织为下面的13个头文件:
<algorithm> , <deque>,functional>,<iterator>,<array>
<vector>,<list>,<forward_list>,<map>,<unordered_map>
<memory>,<numeric>,<queue>,<set>,<unordered_set>,
<stack>,<utility>
中文名:标准模板库
属性:模板库
包括:容器
STL可分为,容器,迭代器,空间配置器,配接器,算法,防函数六个部。
容器:
在实际的开发过程中,数据结构本身的重要性不会逊于操作于数据结构的算法的重要性,当程序中存在着 对时间要求很高的部分 时,数据结构的选择就显得更加重要。
经典的数据结构数量有限,但是我们常常 重复着一些为了实现向量、链表等结构而编写的代码 ,这些代码都十分相似,只是为了适应不同数据的变化而在细节上有所出入。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>
迭代器:
下面要说的迭代器从作用上来说是最基本的部分,可是理解起来比前两者都要费力一些(至少笔者是这样)。软件设计有一个基本原则,所有的问题都可以通过引进一个间接层来简化,这种简化在STL中就是用迭代器来完成的。概括来说,**迭代器在STL中用来将算法和容器联系起来,起着一种黏和剂的作用。**几乎STL提供的所有算法都是通过迭代器存取元素序列进行工作的,每一个容器都定义了其本身所专有的迭代器,用以存取容器中的元素。
迭代器部分主要由头文件<utility>,<iterator>和<memory>组成。
<utility>是一个很小的头文件,它包括了贯穿使用在STL中的几个模板的声明,
<iterator>中提供了迭代器使用的许多方法,
而对于<memory>的描述则十分的困难,它以不同寻常的方式
为容器中的元素分配存储空间,同时也为某些算法执行期间产
生的临时对象提供机制,<memory>中的主要部分是模板类allocator,
它负责产生所有容器中的默认分配器。
算法:
大家都能取得的一个共识是函数库对数据类型的选择对其可重用性起着至关重要的作用。举例来说,一个求方根的函数,在使用浮点数作为其参数类型的情况下的可重用性肯定比使用整型作为它的参数类型要高。而C++通过模板的机制允许推迟对某些类型的选择,直到真正想使用模板或者说对模板进行特化的时候,STL就利用了这一点提供了相当多的有用算法。它是在一个有效的框架中完成这些算法的——你可以将所有的类型划分为少数的几类,然后就可以在模版的参数中使用一种类型替换掉同一种类中的其他类型。
STL提供了大约100个实现算法的模版函数,比如算法for_each将为指定序列中的每一个元素调用指定的函数,stable_sort以你所指定的规则对序列进行稳定性排序等等。这样一来,只要我们熟悉了STL之后,许多代码可以被大大的化简,只需要通过调用一两个算法模板,就可以完成所需要的功能并大大地提升效率。
算法部分主要由头文件<algorithm>,<numeric>和<functional>组成。
<algorithm>是所有STL头文件中最大的一个(然而它很好理解),
它是由一大堆模版函数组成的,可以认为每个函数在很大程度上都是独立的,
其中常用到的功能范围涉及到比较、交换、查找、遍历操作、复制、
修改、移除、反转、排序、合并等等。
<numeric>体积很小,只包括几个在序列上面进行简单数学运算的模板函数,
包括加法和乘法在序列上的一些操作。
<functional>中则定义了一些模板类,用以声明函数对象。
string字符串
(1)对比:
(2)定义string
string s1; //默认构造函数,s1为空串
string s2(s1); //将s2初始化为s1的一个副本
string s3("value"); //初始化
string s4(n,'c'); //将s4初始化为字符‘c’的n个副本,就是n个字符c啦
(3)输入,cin,getline(cin,s);
cin>>s1; //读取有效字符,遇到空格结束。
getline(cin,s6); //读取一行字符,直到你按下回车键。当然可以接受\n这个字符串呢
(4)大写转小写:islower(s[i]);还可用于if判断(不是小写输出0)。
(5)转为大写用toupper( );
转为小写用islower( );
还可以用这个判断,看上边的if语句。
然后:
(6)字符串连接:+号的左右必须至少有一个是string对象
深入理解一下字符串连接:+号的左右必须至少有一个是string对象
string s2=s1+","; //是对的,即使一个字符,也要用双引号!!!
string s3="asd"+","; //错的。。不能将两个字符串面值相加
string s4=s1+","+"asd"; //对的,前面两个相加相当于一个string对象
string s6="asd"+"sdf"+s2; //错的
.
(7)字符串的插入:s.insert(2,“asd”);
用 s.insert(开始插入的坐标,要插入的字符串);
(8)字符串的替换函数:s.replace(起始下标,替换的长度,新的字符串);
用 s.replace(1,5,“loveyou”);,就是从下标1开始连续的5个字符,替换成那个字符串,如果新的这个小字符串超过了5,那就删去原来字符串中下标为1到1+5的字母,添加这个新的字符串,只不过,大的字符串长度会变大呗。。
不够的,就按实际的来呗:
(9)截取字符:s.substr(起始下标,长度);
s.substr(起始下标,长度);
长度可以省略,就是从这个下标开始,截取到最后一个字符!!
(10)删除函数:s.erase(起始下标,长度);//长度可省略
s.erase(2,3);
长度可以省略,就是删到最后呗!!比如说s.erase(2);
(11)查找函数:
s.find(“as”); 返回发现字符串首次出现的坐标
例题:查找aabbaabbaabbbabba中出现的bb的次数:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s5="aabbaabbaabbbabba";
string s6="bb";
int bg=-1;
int ans=0;
while(s5.find(s6,bg+1)!=string::npos)
//每次都从上一次位置的后一位开始搜索
{
bg=s5.find(s6,bg+1);
ans++;
}
cout<<ans;
return 0;
}
//输出5.
(12)翻转函数:
reverse(s.begin(),s.end());
(13)字符串和数值的相互转换:引入串流ss
头文件sstream
#include<sstream>
stringstream ss; 字符串型的串流,
ss<<s; 箭头指向就是数据的流向,s流入ss中
清空字符串用s.clear();
#include<bits/stdc++.h>
using namespace std;
int main()
{
stringstream ss; //字符串型的串流
string s="123.45";
ss<<s; //箭头指向就是数据的流向,s流入ss中
double a;
ss>>a;
cout<<a<<endl;
cout<<"a/10= "<<a/10<<endl;
ss.clear(); //重复利用要调用clear函数
int b=1234;
string s1;
ss<<b; //总之,ss要写在前边
ss>>s1;
cout<<s1<<endl;
return 0;
}
练习题 橙白时光OJ 1112
题目描述
编写一个程序实现将字符串中的所有"you"替换成"we"
输入:
每行数据是一个字符串,长度不超过1000 数据以EOF结束
输出:
对于输入的每一行,输出替换后的字符串
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
while(getline(cin,s))
{
int pos=s.find("you");
while(pos!=string::npos)
{
s.replace(pos,3,"we");
pos=s.find("you"); //不断更新pos
}
cout<<s<<endl;
}
return 0;
}
vector向量(动态数组)
(1)特征:
和数组一样,可以用下标进行遍历
长度动态增长
末尾插入,末尾删除
(2)基本操作:
声明:
vector<int> vec; //不给长度
vector<int> vec(10); //声明长度为10的vector
vector<int> vec(10,1); //长度为10,初始化为1的vector
内置函数:
vec.size(); //元素个数
vec.empty(); //判断是否为空
vec.push_back();//末尾插入
vec.pop_back(); //末尾删除
vec.begin() //指向第一个元素的指针
vec.end() //指向最后一个元素后一个单元的指针
vec.insert(vec.begin()+1,num); //在下标为1的地方插入num
vec.erase(vec.begin()+1); //删除下标为1的元素
vec.reverse(vec.begin(),vec.end()) //翻转
sort(vec.begin(),vec.end(),cmp); //排序
遍历:
//1.通过下标
vector<int> vec;
for(int i=1;i<=5;i++)
vec.push_back(i);
for(int i=0;i<vec.size();i++)
cout<<vec[i]<<" ";
cout<<endl;
//2.通过迭代器
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<" ";
cout<<endl;
问题描述
Huffman树在编码中有着广泛的应用。在这里,我们只关心Huffman树的构造过程。
给出一列数{pi}={p0, p1, …, pn-1},用这列数构造Huffman树的过程如下:
1. 找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
2. 重复步骤1,直到{pi}中只剩下一个数。
在上面的操作过程中,把所有的费用相加,就得到了构造Huffman树的总费用。
本题任务:对于给定的一个数列,现在请你求出用该数列构造Huffman树的总费用。
例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下:
1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入,得到{5, 8, 9, 5},费用为5。
2. 找到{5, 8, 9, 5}中最小的两个数,分别是5和5,从{pi}中删除它们并将和10加入,得到{8, 9, 10},费用为10。
3. 找到{8, 9, 10}中最小的两个数,分别是8和9,从{pi}中删除它们并将和17加入,得到{10, 17},费用为17。
4. 找到{10, 17}中最小的两个数,分别是10和17,从{pi}中删除它们并将和27加入,得到{27},费用为27。
5. 现在,数列中只剩下一个数27,构造过程结束,总费用为5+10+17+27=59。
输入格式
输入的第一行包含一个正整数n(n< =100)。
接下来是n个正整数,表示p0, p1, …, pn-1,每个数不超过1000。
输出格式
输出用这些数构造Huffman树的总费用。
样例输入
5
5 3 8 2 9
样例输出
59
Source
蓝桥杯
[Submit][Status]
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
vector<int>q;
int a;
int ans=0;
for(int i=1;i<=n;i++)+
{
cin>>a;
q.push_back(a);
}
while(q.size()>1)
{
sort(q.begin(),q.end()); //默认从小到大排序
int i=q[0];//访问的话,就直接数组访问就好啦
q.erase(q.begin());
int j=q[0];
q.erase(q.begin());
q.push_back(i+j);
ans += i+j;
}
cout<<ans;
return 0;
}
3019.3.19晚课习题
/*
//哈夫曼树
//就是上边内个题
//找到{pi}中最小的两个数,设为pa和pb,将pa和pb从{pi}中删除掉,
//然后将它们的和加入到{pi}中。这个过程的费用记为pa + pb。
//2. 重复步骤1,直到{pi}中只剩下一个数
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(int a,int b)//vector的排序
{
return a>b;
}
int main()
{
int n;
cin>>n;
vector<int>q;
int a;
int ans=0;
for(int i=1;i<=n;i++)
{
cin>>a;
q.push_back(a);
}
while(q.size()>1)
{
//方法一
sort(q.begin(),q.end()); //默认从小到大排序也行
int i=q[0];//访问的话,就直接数组访问就好啦
q.erase(q.begin());
int j=q[0];
q.erase(q.begin());
q.push_back(i+j);
//方法二
//学姐讲的方法
//从大到小排序
sort(q.begin(),q.end(),cmp);
int t=q[q.size()-1]+q[q.size()-2];
q.pop_back();
q.pop_back();
q.push_back(t);
ans += t;
}
cout<<ans;
return 0;
}
*/
/*
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//sort 函数排序
struct stu
{
string zz;//姓名
int z,a,b,c;//总分,语文,数学,英语
}I[105];
bool cmp(stu a,stu b)
{
if(a.z==b.z)//按照总分大的排序,总分一样的话,按照语文从大到小排序,,,,,,
{
if(a.a==b.a)
{
if(a.b==b.b)
return a.c>b.c;
return a.b>b.b;
}
return a.a>b.a;
}
return a.z>b.z;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>I[i].zz>>I[i].z>>I[i].a>>I[i].b>>I[i].c;
sort(I,I+n,cmp);
for(int i=0;i<n;i++)
cout<<I[i].zz<<' '<<I[i].z<<' '<<I[i].a<<' '<<I[i].b<<' '<<I[i].c<<endl;
return 0;
}
*/
/*
//输入n个字符串,然后按照以下规则输出 对称 的字符串
//规则:优先输出长度小的,如果长度相等,输出字典序小的
//有可能输入空格
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//排序!!!!!!!!!!!!
bool cmp(string a,string b)
{
return a.length()!=b.length()? a.length()<b.length():a<b;
}
int main()
{
int n;
cin>>n;
getchar();//别忘记
string s;//输入的
string temp;//交换的
vector<string>v;//用动态数组存储将要输出的对称的字符串
for(int i=0;i<n;i++)
{
getline(cin,s);
temp=s;//string直接赋值
reverse(temp.begin(),temp.end());//翻转
if(s==temp)
v.push_back(s);
}
sort(v.begin(),v.end(),cmp);//对vector进行sort排序
for(int i=0;i<v.size();i++)
cout<<v[i]<<endl;//直接输出
return 0;
}
*/
/*
//输入几个人名,输出一共有多少个人(不重复)
//map自身去重
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
string s;
map<string,int>a;//定义map!!!!!!!!!!!!!!!!!!
while(n--)
{
cin>>s;
a[s]=1;//直接赋值进去
}
cout<<a.size();
return 0;
}
*/
/*
//输入几个人名,输出人名和此人名出现的次数
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
string s;
map<string,int>a;
set<int>::iterator it;//迭代器
while(n--)
{
cin>>s;
if(a.count(s))//如果a中已经有这个人名了,数值就+1
a[s]++;
else //如果没有这个人,就把这个人加到set中去,然后赋值1
a[s]=1;
}
//iterator
//输出!!!!!!!!!!!!
for(auto it=a.begin();it!=a.end();it++)
cout<<it->first<<' '<<it->second<<endl;
return 0;
}
*/