六大组件:
容器,算法,迭代器,仿函数,适配器,空间配置器


容器分类:

算法分类:

迭代器
vector,deque,list,set,map有迭代器:
vector,为动态空间,原迭代器在扩容后会失效
deque的迭代器很复杂,所以用的少
list,迭代器不会因为插入和删除操作而失效
set,map的迭代器为只读迭代器,不会失效,不能通过迭代器修改数据
stack,queue没有迭代器
分类

遍历
一般遍历:
vector 可以用下标遍历
void print(int x)
{
cout<<x<<endl;
}
int main()
{
vector<int> a;
a.push_back(1);
a.push_back(3);
a.push_back(3);
vector<int>::iterator itstart=a.begin();
vector<int>::iterator itend=a.end();
// for(;itstart!=itend;itstart++)
// cout<<*itstart<<endl;
for_each(it_start,it_end,print);
return 0;
}
自定义类遍历:
class Person
{
public :
Person(int age)
{
this->age=age;
}
int age;
};
void print(Person &a)
{
cout<<a.age<<endl;
}
void test()
{
Person p1(1);
Person p2(4);
Person p3(11);
Person p4(13);
vector<Person> v;
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
vector<Person>::iterator itstart=v.begin();
vector<Person>::iterator itend=v.end();
for(;itstart!=itend;itstart++)
{
print(*itstart);
}
}
int main()
{
test();
return 0;
}
迭代器指向为容器
test2()
{
vector <int> v1;
vector<int> v2;
vector<vector<int> > vsum;
v1.push_back(1);v1.push_back(4);
v2.push_back(3);v2.push_back(12);
vsum.push_back(v1);vsum.push_back(v2);
vector<vector<int> >::iterator itstart=vsum.begin();
for(;itstart!=vsum.end();itstart++)
{
for(vector<int>::iterator it=(*itstart).begin();it!=(*itstart).end();it++)
{
cout<<*it<<" ";
}
cout<<endl;
}
}
int main()
{
// test();
test2();
return 0;
}
常用容器
String容器

赋值



拼接:
注释部分都是可以的

查找:
find()从左往右找
rfind()从右往左找
找到返回对应下标
找不到返回一个很大的数

比较:

获取子串:
s.substr(x,y) 从x位置开始的y个字符

插入删除:
s.erase(x,y) 删除在x位置开始的y个字符

string和char的转化

Vector容器

迭代器:可以随机访问
还有反向迭代器,++为往前挪


构造函数:

赋值:
交换操作,实际中是交换了指针指的位置。

大小的对应操作:
resize(int num) 重新指定容器长度但是容量不变,变短,保留前num个,变长,默认为0
resize(int num,int x) 与上一样,变长,默认为x

存取查找操作:
二分查找返回下标迭代器:可以用在vector,普通数组,set,map
利用二分查找的方法在一个排好序的数组中进行查找的。(如果没有排好序,也是从头往后找的结果)
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
在从大到小的排序数组中,重载lower_bound()和upper_bound()
lower_bound( begin,end,num,greater< type >() ):从数组的begin位置到end-1位置二分查找第一个小于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num,greater< type >() ):从数组的begin位置到end-1位置二分查找第一个小于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
查询vector是否有某个数
vector<int> v;
v.push_back(1231);
v.push_back(124242352);
v.push_back(123);
sort(v.begin(),v.end());
int idx=lower_bound(v.begin(),v.end(),1231)-v.begin();
if(v[idx]==123) cout<<"havs";
查询数组是否有某个数
int num[6]={1,2,4,2,15,34};
sort(num,num+6);
int idx=lower_bound(num,num+6,4)-num;
if(num[idx]==4) cout<<"has";
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
const int INF=2*int(1e9)+10;
#define LL long long
int cmd(int a,int b){
return a>b;
}
int main(){
int num[6]={1,2,4,7,15,34};
sort(num,num+6); //按从小到大排序
int pos1=lower_bound(num,num+6,7)-num; //返回数组中第一个大于或等于被查数的值
int pos2=upper_bound(num,num+6,7)-num; //返回数组中第一个大于被查数的值
cout<<pos1<<" "<<num[pos1]<<endl;
cout<<pos2<<" "<<num[pos2]<<endl;
sort(num,num+6,cmd); //按从大到小排序
int pos3=lower_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于或等于被查数的值
int pos4=upper_bound(num,num+6,7,greater<int>())-num; //返回数组中第一个小于被查数的值
cout<<pos3<<" "<<num[pos3]<<endl;
cout<<pos4<<" "<<num[pos4]<<endl;
return 0;
}

插入删除:

使用swap收缩容量

用resize()预留空间:
不提琴预留足够大的空间,capacity会多次开辟空间

排序:


自定义类型:

list
一、List定义:
List是stl实现的双向链表,与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢。使用时需要添加头文件
#include
二、List定义和初始化:
list<int>lst1; //创建空list
list<int> lst2(5); //创建含有5个元素的list
list<int>lst3(3,2); //创建含有3个元素的list
list<int>lst4(lst2); //使用lst2初始化lst4
list<int>lst5(lst2.begin(),lst2.end()); //同lst4
三、List常用操作函数:
Lst1.pop_back() 删除最后一个元素
Lst1.pop_front() 删除第一个元素
Lst1.push_back() 在list的末尾添加一个元素
Lst1.push_front() 在list的头部添加一个元素
Lst1.back() 返回最后一个元素
Lst1.begin() 返回指向第一个元素的迭代器
Lst1.clear() 删除所有元素
Lst1.end() 返回末尾的迭代器
Lst1.assign() 给list赋值
Lst1.erase() 删除一个元素 迭代器
Lst1.front() 返回第一个元素
Lst1.remove() 从list删除元素
Lst1.empty() 如果list是空的则返回true
Lst1.get_allocator() 返回list的配置器
Lst1.insert() 插入一个元素到list中
Lst1.max_size() 返回list能容纳的最大元素数量
Lst1.merge() 合并两个list
Lst1.rbegin() 返回指向第一个元素的逆向迭代器
Lst1.remove_if() 按指定条件删除元素
Lst1.rend() 指向list末尾的逆向迭代器
Lst1.resize() 改变list的大小
Lst1.reverse() 把list的元素倒转
Lst1.size() 返回list中的元素个数
Lst1.sort() 给list排序
Lst1.splice() 合并两个list
Lst1.swap() 交换两个list
Lst1.unique() 删除list中重复的元素
四、List使用示例:
示例1:遍历List
//迭代器法
for(list::const_iteratoriter = lst1.begin();iter != lst1.end();iter++)
{
cout<<*iter;
}
cout<<endl;
示例2:
#include
#include
#include
#include
#include <windows.h>
using namespace std;
typedef list LISTINT;
typedef list LISTCHAR;
void main()
{
//用LISTINT创建一个list对象
LISTINT listOne;
//声明i为迭代器
LISTINT::iterator i;
listOne.push_front(3);
listOne.push_front(2);
listOne.push_front(1);
listOne.push_back(4);
listOne.push_back(5);
listOne.push_back(6);
cout << "listOne.begin()--- listOne.end():" << endl;
for (i = listOne.begin(); i != listOne.end(); ++i)
cout << *i << " ";
cout << endl;
LISTINT::reverse_iterator ir;
cout << "listOne.rbegin()---listOne.rend():" << endl;
for (ir = listOne.rbegin(); ir != listOne.rend(); ir++) {
cout << *ir << " ";
}
cout << endl;
int result = accumulate(listOne.begin(), listOne.end(), 0);
cout << "Sum=" << result << endl;
cout << "------------------" << endl;
//用LISTCHAR创建一个list对象
LISTCHAR listTwo;
//声明i为迭代器
LISTCHAR::iterator j;
listTwo.push_front('C');
listTwo.push_front('B');
listTwo.push_front('A');
listTwo.push_back('D');
listTwo.push_back('E');
listTwo.push_back('F');
cout << "listTwo.begin()---listTwo.end():" << endl;
for (j = listTwo.begin(); j != listTwo.end(); ++j)
cout << char(*j) << " ";
cout << endl;
j = max_element(listTwo.begin(), listTwo.end());
cout << "The maximum element in listTwo is: " << char(*j) << endl;
Sleep(10000);
}
#include
#include
#include <windows.h>
using namespace std;
typedef list INTLIST;
//从前向后显示list队列的全部元素
void put_list(INTLIST list, char *name)
{
INTLIST::iterator plist;
cout << "The contents of " << name << " : ";
for (plist = list.begin(); plist != list.end(); plist++)
cout << *plist << " ";
cout << endl;
}
//测试list容器的功能
void main(void)
{
//list1对象初始为空
INTLIST list1;
INTLIST list2(5, 1);
INTLIST list3(list2.begin(), --list2.end());
//声明一个名为i的双向迭代器
INTLIST::iterator i;
put_list(list1, "list1");
put_list(list2, "list2");
put_list(list3, "list3");
list1.push_back(7);
list1.push_back(8);
cout << "list1.push_back(7) and list1.push_back(8):" << endl;
put_list(list1, "list1");
list1.push_front(6);
list1.push_front(5);
cout << "list1.push_front(6) and list1.push_front(5):" << endl;
put_list(list1, "list1");
list1.insert(++list1.begin(), 3, 9);
cout << "list1.insert(list1.begin()+1,3,9):" << endl;
put_list(list1, "list1");
//测试引用类函数
cout << "list1.front()=" << list1.front() << endl;
cout << "list1.back()=" << list1.back() << endl;
list1.pop_front();
list1.pop_back();
cout << "list1.pop_front() and list1.pop_back():" << endl;
put_list(list1, "list1");
list1.erase(++list1.begin());
cout << "list1.erase(++list1.begin()):" << endl;
put_list(list1, "list1");
list2.assign(8, 1);
cout << "list2.assign(8,1):" << endl;
put_list(list2, "list2");
cout << "list1.max_size(): " << list1.max_size() << endl;
cout << "list1.size(): " << list1.size() << endl;
cout << "list1.empty(): " << list1.empty() << endl;
put_list(list1, "list1");
put_list(list3, "list3");
cout << "list1>list3: " << (list1 > list3) << endl;
cout << "list1<list3: " << (list1 < list3) << endl;
list1.sort();
put_list(list1, "list1");
list1.splice(++list1.begin(), list3);
put_list(list1, "list1");
put_list(list3, "list3");
Sleep(10000);
}
deque容器
vector只有尾插,尾删,为单向开口的连续内存空间。
deque则是双向开口的连续线性空间


构造函数:

赋值操作:
d.assign(n,x) 赋值n个x

大小操作:

双端操作:

取值:

插入操作:
pos对应的是迭代器,不是int数值



删除:

stack容器
先进后出

没有迭代器:

基本操作:

queue容器:
先进先出
### 没有迭代器:

基本操作:

例子:

priority_queue 优先队列
优先队列的用法
priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数:
priority_queue<Type, Container, Functional>
其中Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
#include <iostream>
#include <queue>
using namespace std;
int main(){
priority_queue<int> q;
for( int i= 0; i< 10; ++i ) q.push( rand() );
while( !q.empty() ){
cout << q.top() << endl;
q.pop();
}
getchar();
return 0;
}
如果要用到小顶堆,则一般要把模板的三个参数都带进去。
STL里面定义了一个仿函数 greater<>,对于基本类型可以用这个仿函数声明小顶堆
#include <iostream>
#include <queue>
using namespace std;
int main(){
priority_queue<int, vector<int>, greater<int> > q;
for( int i= 0; i< 10; ++i ) q.push( rand() );
while( !q.empty() ){
cout << q.top() << endl;
q.pop();
}
getchar();
return 0;
}
对于自定义类型,则必须自己重载 operator< 或者自己写仿函数
#include <iostream>
#include <queue>
using namespace std;
struct node
{
int x,y;
node(int xx,int yy):x(xx),y(yy){
}
bool operator<(const node &cmp)const{
return x>cmp.x;//升序,为小根堆
}
};
int main(){
priority_queue<node> q;
// for( int i= 0; i< 10; ++i )
// q.push( Node( i/2,i*3) );
q.push(Node(3,3));
q.push(Node(3,13));
q.push(Node(3,1));
q.push(Node(1,1));
while( !q.empty() ){
cout << q.top().x << ' ' << q.top().y << endl;
q.pop();
}
return 0;
}
自定义类型重载 operator< 后,声明对象时就可以只带一个模板参数。 重载函数operator< 也可以放到Node结构体申明里,但要加friend修饰
但此时不能像基本类型这样声明
priority_queue<Node, vector, greater >;
原因是 greater 没有定义,如果想用这种方法定义 则可以按如下方式:
#include <iostream>
#include <queue>
using namespace std;
struct Node{
int x, y;
Node( int a= 0, int b= 0 ):
x(a), y(b) {}
};
struct cmp{
bool operator() ( Node a, Node b ){
if( a.x== b.x ) return a.y> b.y;
return a.x> b.x; }//为升序
//return a.x<b.x; 为降序
};
int main(){
priority_queue<Node, vector<Node>, cmp> q;
for( int i= 0; i< 10; ++i )
q.push( Node( rand(), rand() ) );
while( !q.empty() ){
cout << q.top().x << ' ' << q.top().y << endl;
q.pop();
}
getchar();
return 0;
}
//以上代码实现的是一个小顶堆
自实现优先队列
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class priority_queue
{
private:
vector<int> data;
public:
void push( int t ){
data.push_back(t);
push_heap( data.begin(), data.end());
}
void pop(){
pop_heap( data.begin(), data.end() );
data.pop_back();
}
int top() { return data.front(); }
int size() { return data.size(); }
bool empty() { return data.empty(); }
};
int main()
{
priority_queue test;
test.push( 3 );
test.push( 5 );
test.push( 2 );
test.push( 4 );
while( !test.empty() ){
cout << test.top() << endl;
test.pop();
}
return 0;
}
list容器:
链表物理存储单元上非连续,非顺序的存储结构。 为双向链表



迭代器:

list为双向循环链表的验证:
会打印出两遍0-9.

基本操作:






自定义类型排序:


set容器和multiset容器:
自动排序+去重 其中的迭代器为只读迭代器。


基本操作:


例子:


修改排序
默认为从小到大,
set<int,greater<int> > a;//降序
set<int> a;//默认为升序,等同set<int,less<int> > a;


取数:
set<int>::iterator it;
// 用auto 也行
for(it=s.begin();it!=s.end();it++) //使用迭代器进行遍历
{
printf("%d\n",*it);
}
pair对组(也不算是容器)
声明方式:

常用方式
pair<int,string> num_str[]={
{1000, "M"},
{900, "CM"},
{500, "D"},
};
for(auto [k,v]:num_str){
}
map/multimap容器

基本操作:
插入数据:


遍历取值操作:
//map遍历按key从小到大
map<string,int>::iterator it=map.begin();
it->first it->second;
(*it).first (*it).second;
// unordered_map 遍历随机
unordered_map<int,string> mp;
mp[1] = "apple";
for(auto it=mp.begin();it!=mp.end();it++)
使用正向,反向迭代器遍历。或者用数组遍历。
常用:
正向:
for(auto it=m1.begin();it!=m1.end();it++){
printf(" %d %.1lf",it->x,it->y);
}
反向:
for(auto it=m1.end();it!=m1.begin();){
--it;
printf(" %d %.1lf",it->x,it->y);
}
int main(){
map<int,string> mapStudent;
mapStudent[1] = "student_one";
mapStudent[2] = "student_two";
mapStudent[3] = "student_three";
map<int, string>::reverse_iterator iter;
for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++){
cout<<iter->first<<" "<<iter->second<<endl;
}
return 0;
}

修改排序规则:
默认为按键值升序:

二维容器:
1,常用
vector<int> a[1000];
a[1].push_back(1);
2,非常用
vector<vector<int> > v;
//要使用指定位置存值,就要先resize ,但是用了哪一层用了resize ,那一层就不能用push_back
//第一层,第二层都使用resize,就不能使用push_back() 放不进去的
v.resize(100);
v[1].resize(100);
v[1][1]=2;//不能使用push_back() 放不进去的
// 第一层使用resize,第二层不使用,可以用push_back()存值
v[1].push_back(1);
v[1].push_back(2);
v[1].push_back(3);
v[1].push_back(4);
cout<<v[1][1];
容器的复制拷贝:
复制容器(container)元素, 可以使用标准库(STL)的copy()和copy_n()函数.
在我们要初始化一个容器为另一个容器的拷贝时,如果不适用迭代器,直接使用容器变量名进行拷贝只能拷贝相同容器类型的
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{
list<int> l = {1, 2, 3};
list<int> v(l);
//vector<int> v1(l); //出错
for(auto i : v)
{
cout << i << endl;
}
return 0;
}
如果要拷贝不同容器类型的时候我们要使用迭代器来进行容器内范围拷贝
#include <iostream>
#include <vector>
#include <list>
using namespace std;
int main()
{
list<int> l = {1, 2, 3};
vector<int> v(l.begin(), l.end());
for(auto i : v)
{
cout << i << endl;
}
return 0;
}
STL容器使用时机:



函数对象

class Compare
{
public:
bool operator()(int a,int b)
{
return a>b;
}
};
void test11()
{
vector<int> a;
a.push_back(1);
a.push_back(12);
a.push_back(3);
sort(a.begin(),a.end(),Compare());
for(int i=0;i<a.size();i++)
{
cout<<a[i]<<endl;
}
}
谓词:
boolean为返回追的函数对象

bool greater2(int a)
{
return a>2;
}
void test11()
{
vector<int> a;
a.push_back(1);
a.push_back(12);
a.push_back(3);
//find_if()返回一个迭代器
vector<int>::iterator it=find_if(a.begin(),a.end(),greater2);
if(it!=a.end())
{
cout<<*it<<endl;
}
}
int main()
{
test11();
return 0;
}
内建函数对象



函数对象适配器


完整例题:
L2-005 集合相似度

int n;
set<int> u[60];
void fun(int a,int b)
{
int scnt=0;
set<int>::iterator it;
for(it=u[a].begin();it!=u[a].end();it++)
{
if(u[b].find(*it)!=u[b].end()) scnt++;
}
int sum=u[a].size()+u[b].size()-scnt;
printf("%.2f%%\n",scnt*1.0/sum*100);
}
int main()
{
cin>>n;
int k;
for(int i=0;i<n;i++)
{
cin>>k;
for(int j=0;j<k;j++)
{
int a;
cin>>a;
u[i+1].insert(a);
}
}
int m;
cin>>m;
while(m--)
{
int s;int ss;
cin>>s>>ss;
fun(s,ss);
}
return 0;
}
L2-015

#include<iostream>
#include<set>
using namespace std;
int main()
{
int n;
cin>>n;
set<int> s;
for(int i=0;i<n;i++)
{
int t;
cin>>t;
set<int>::iterator it=s.lower_bound(t);
if(it!=s.end())
{
s.erase(it);
}
s.insert(t);
}
cout<<s.size();
return 0;
}
L2-015:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const double eps = 1e-8; //const只是用来定义常量,常量在代码中一直存在,但define是预处理功能,有本质区别
const int maxx = 0x7f7f7f7f;//0x7f7f7f7f表示数据的无穷大
//常用的浮点数比较宏定义:
#define Equ(a,b) ((fabs((a)-(b)))<(eps)) //等于
#define More(a,b) (((a)-(b))>(esp)) //大于
#define Less(a,b) (((a)-(b))<(-esp))//小于
#define MoreEqu(a,b) (((a)-(b))>(-esp))//大于等于
#define LessEqu(a,b) (((a)-(b))<(esp))//小于等于
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )//
//使用了algorithm头文件就可以直接使用max函数;
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
#define ll long long
#define PI 3.1415926
#define eps 1e-8
#define Conn(x,y) x##y;
int n;
int k;
int m;
int main()
{
cin>>n>>k>>m;
vector<double> v;
for(int i=0;i<n;i++)
{
int minn=200;
int maxx=-1;
double sum=0;
for(int j=0;j<k;j++)
{
int x;cin>>x;
sum+=x;
minn=min(minn,x);
maxx=max(maxx,x);
}
sum=(sum-minn-maxx)/(k-2);
v.push_back(sum);
}
sort(v.begin(),v.end());
int start=n-m;
for(int i=start;i<v.size();i++)
{
if(i!=v.size()-1)
printf("%.3lf ",v[i]);
else printf("%.3lf",v[i]);
}
return 0;
}
C语言STL标准模板库——容器详解
本文详细介绍了C++的STL容器,包括String、Vector、List、Deque、Set、Map等,讲解了它们的特点、遍历方式、插入删除操作、排序规则以及在实际编程中的使用技巧,如迭代器的使用、容器的复制拷贝和函数对象等。
2万+

被折叠的 条评论
为什么被折叠?



