[C++]那些年被虐的STL

首先很感谢P1135奇怪的电梯
【2.14补充:此题已被AC!然后将被我花式虐[From语]哈哈哈哈哈哈哈哈哈哈好嗨哟感觉人生已经到达了巅峰感觉人生已经到达了高潮】这道题了!在做这道题的我大致就是下图qwq:

dfs—>sp—>bfs—>stl

于是小蒟蒻准备写一篇博客整理一下STL库啦!

祭出大佬@From 廿八——初六每日更新

目录:

  • vector

    封装数组

    #### 向量(vector) 连续存储的元素

  • set

    封装二叉树【集合】

    集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用于元素对的谓词排列,没有两个不同的元素能够拥有相同的次序
  • queue

    队列(queue)【包括优先队列priority_queue】 先进先出的值的排列
  • stack

    栈(stack) 后进先出的值的排列
  • map

    封装二叉树

    映射(map) 由{键,值}对组成的集合,以某种作用于键对上的谓词排列
  • algorithm?lower_bound?upper_bound?【待定】


# VECTOR

## 参考:
C++ STL vector详解

C++vector的使用总结及常用vector操作

C++中vector用法的详细说明

## 解释:
进化的动态数组:不用考虑会不会浪费内存或者越界

## 特点:
==可分配拓展的数组。随机访问快,在中间插入和删除慢,末端插入和删除快

##### vector可以分为STL方式和类数组方式,由于本蒟蒻太水了然后先重点讲类数组方式呐【STL方式看懂了再补上呐】

然而这些和实际操作并没有什么关系~!完全可以当数组用呐~!

用法

头文件

#include<vector>

定义方式

vector<int>v1;//vector元素为int型
vector<node>v2;//自定义结构体
vector<int>v3(a,b)//声明一个初始大小为a且初始值都为b的向量
//【向量:一个存放数据的地方,类似于一维数组和链表】
vector<int>::iterator it;//定义一个迭代器
/*【迭代器:in a word 是一个复杂的指针,
通过“*”,“++”,“==”,“!=”,“=”遍历数组,
开氧气优化会很快很快(set,map只能用迭代器遍历)。如iter==a.end()】*/

常规操作

vector<int>v1;

v1.push_back()  /*在数组的最后添加一个数据*/

v1.pop_back()     /*去掉数组的最后一个数据 */

v1.front()     /*返回第一个元素(栈顶元素)*/

v1.begin()        /*得到数组头的指针,用迭代器接受*/

v1.end()          /*得到数组的最后一个单元+1的指针,用迭代器接受*/

v1.clear()        /* 移除容器中所有数据*/

v1.empty()        /*判断容器是否为空*/

v1.erase(pos)     /*删除pos位置的数据【慢】*/

v1.erase(beg,end) /* 删除[beg,end)区间的数据【慢】*/

/*考虑到erase过慢所以尽量不要用erase*/

v1.size()         /*返回容器中实际数据的个数*/

v1.insert(pos,data)/*在pos处插入数据【data:要插入的数】*/

for(int i=0;i<int(v1.size());++i)   /*循环遍历【不这么写会发出橙红色的警告√】*/

栗子

P1540 机器翻译

用vector模拟队列√

#include<bits/stdc++.h>
using namespace std;
int M,N,ans;
vector<int>dic;
vector<int>text;
int main(){
    cin>>M>>N;
    int cinn;
    for(int i=1;i<=N;i++){
        cin>>cinn;
        text.push_back(cinn);}
    for(int i=0;i<int(text.size());++i){
        bool flag=false;
        for(int j=0;j<int(dic.size());++j)
            if(text[i]==dic[j]) flag=true;
        if(!flag){
            if(int(dic.size())-1<M-1){
                dic.push_back(text[i]);
                ans++;}
            else{
                dic.push_back(text[i]);
                for(int j=0;j<int(dic.size())-1;++j)
                    dic[j]=dic[j+1];
                dic.pop_back();
                ans++;}}}
    cout<<ans;
    return 0;
}

【vector暂且告一段落,等到所有都整好之后再来做批注和修改呐】


SET

前面der补充:

今天From大佬向小蒟蒻介绍了一个特别神奇的东西——修改语言标准

工具—>编译选项—>在连接器命令行加入以下命令—>语言标准

【图片中为“-std=c++11”】

是不是觉得在哪里见到过?没错就是这里!

From:“这样改之后就会舒服很多啦!比如:

迭代器可以直接用auto 定义

遍历vector可以这样:

vector<int> s
for (auto it : s)

虽然说还不是很会用8但是以后可以慢慢用起来呢!明明就是你蠢qwq

好啦下面正式进入set!

参考

解释

set是用红黑树【很高级的东西,emmm有兴趣请百度】的一种高级数据结构,可以类比于数学中的集合。

“除了没有单独的键,set 容器和 map 容器很相似。定义 set 的模板有 4 种,其中两种默认使用 less 来对元素排序,另外两种使用哈希值来保存元素。有序 set 的模板定义在 set 头文件中。无序 set 的模板定义在 unordered_set 头文件中。因此有序 set 包含的元素必须支持比较运算,无序 set 中的元素必须支持哈希运算。”

真好又发现一个不会的了——哈希

特点

  • 集合,最大的特点就是其中的元素不能重复,所以用set的时候可以判断元素是否重复再进入【此特点在下面的例题中可以充分显示】。
  • set中的元素都是排好序的

用法

头文件

#include<set>

所以STL里的头文件都是有规律的8

定义方式

同vector

set<node>s
set<int>::iterator it;

set不能用下角标遍历,所以每次都要写迭代器

当set集合中的元素为结构体时,该结构体必须实现运算符‘<’的重载???【没懂】

常规操作

set<int> s;

s.begin();       //返回set容器的第一个元素

s.end();      //返回set容器的最后一个元素

s.clear();      //删除set容器中的所有的元素

s.empty();     //判断set容器是否为空

s.max_size();   //返回set容器可能包含的元素最大个数

s.size();     //返回当前set容器中的元素个数

s.rbegin();    //返回的值和end()相同

s.rend();     //返回的值和rbegin()相同

s.find();        //返回一个指向被查找到元素的迭代器

s.insert();      //在集合中插入元素

添加,删除,插入

由于c++11还是没能很适应,暂且看不懂里面的代码emmm
添加,删除,插入

栗子

P4305不重复数字

//快读吸氧必选其一
#include<bits/stdc++.h>
using namespace std;
int T,N;
long long num;
set<long long> s;
vector<long long> v;
int main(){
    cin>>T;
    while(T--){
        v.clear();
        s.clear();
        scanf("%d",&N);
        for(int j=1;j<=N;++j){
            cin>>num;
            if(s.find(num)==s.end()){
            v.push_back(num);
            s.insert(num);}
        }
        for(int j=0;j<int(v.size());++j)
            cout<<v[j]<<" ";
        cout<<endl;
    }
    return 0;
}

MAP

Ps:由于map和set很像所以先将map提上来讲呐 明明是From大佬发烧穿越了好8

参考

解释

顾名思义,给你张地图去查找。map的主要用处也就是查找。同时也是一个集合,即和set一样,每个元素只能在集合中出现一次。并且根据key在内部自动排序【应该是为了查找方便吧emmm】

map是STL的一个关联容器,它提供一对一的hash。[所以hash有什么用emmm]

map中通常需要pair:

第一个可以称为关键字(key),每个关键字只能在map中出现一次;

第二个可能称为该关键字的值(value);

类比一下,就像你的学号与你的名字对应一样。

用法

定义方式

map<node,node> m;
map<node1,node2>::iterator iter;//node1为索引,node2为相关联的指针

头文件

#include<map>

常规操作

```cpp
map<int, string> m;

m.begin()         //返回指向map头部的迭代器

m.clear()        //删除所有元素

m.count()         //返回指定元素出现的次数

m.empty()         //如果map为空则返回true

m.end()           //返回指向map末尾的迭代器

m.equal_range()   //返回特殊条目的迭代器对

m.erase()         //删除一个元素

m.find()          //查找一个元素

m.get_allocator() //返回map的配置器

m.insert()        //插入元素

m.key_comp()      //返回比较元素key的函数

m.lower_bound()   //返回键值>=给定元素的第一个位置

m.max_size()      //返回可以容纳的最大元素个数

m.rbegin()        //返回一个指向map尾部的逆向迭代器

m.rend()          //返回一个指向map头部的逆向迭代器

m.size()          //返回map中元素的个数

m.swap()           //交换两个map

m.upper_bound()    //返回键值>给定元素的第一个位置

m.value_comp()     //返回比较元素value的函数

for(iter = m.begin(); iter != mapStudent.end(); iter++)
//前项遍历map

```

其中的插入元素的方法有三种【emmm三种对我来说都还有问题】

map<int,?string>?mapStudent;

// 第一种 用insert函數插入pair【那是不是又得定义一个pair啦?】

mapStudent.insert(pair<int, string>(000, "student_zero"));

// 第二种 用insert函数插入value_type数据【基本不用】

mapStudent.insert(map<int, string>::value_type(001, "student_one"));

// 第三种 用"array"方式插入【咳咳array是Java里的数组的名称,类似于vector】

mapStudent[123] = "student_first";
mapStudent[456] = "student_second";

//insert和数组的插入的区别在于,insert的时候如果以前有这个值,那么插入不了;而数组可以覆盖掉这个值

然后是map的查找功能啦

  • count判断关键字是否出现。【因为集合的特性,所以只能返回0或1】
  • 用迭代器接收 find() 寻找到的东西。通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first和 iterator->second分别代表关键字和存储的数据。
  • lower_bound函数用法,这个函数用来返回要查找关键字的下界(是一个迭代器)

    upper_bound函数用法,这个函数用来返回要查找关键字的上界(是一个迭代器)

    例如:map中已经插入了1,2,3,4的话,如果lower_bound(2)的话,返回的2,而upper-bound(2)的话,返回的就是3

栗子

让气球飞

#include<iostream>
#include<map>
#include<string>
using namespace std;
int n;
string str;
int main(){
    map<string,int> m;
    while(cin>>n,n!=0){
        string ans;
        int maxn=-1;
        m.clear();
        while(n--){
            cin>>str;
            m[str]++;
            if(m[str]>maxn){
                maxn=m[str];
                ans=str;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

备注

map不能用sort!

STACK

参考

解释

先进后出,注意与队列区分,不多加解释了

用法

由于和From大佬聊得太久再加上我想睡觉后者是主要原因,所以用法合在一起写辽

#include<stack>//头文件

stack<int> s;//定义
//stack没有迭代器,queue也是

s.push();//入栈
s.pop();//出栈
s.top();//访问栈顶
s.empty();//判断栈是否为空
s.size();//返回栈中的元素个数

【下面是stack的用法图解,内含deque】

栗子

P1115最大子段和
P1449后缀表达式


2.14补充

常用库函数

include

//因为bits库包含的东西过多,所以编译时间会比较长(yxc:肉眼可见的慢)

  • sort [不稳定排序]

//扩充成pair【a[i]=>pair<int,int>】可以手动稳定

//两个vector可以进行sort排序比较。sort很厉害的呢!【sort不只是快速排序,是一堆排序一起的】

  • stable_sort [稳定排序]
  • min/max [只要支持小于号的东西都可以使用]

//if语句先判断,问号表达式先把?后面的算出来再判断?前面的东西。【可能编译器已经优化过了emmm】

//*1ll long long 类型常量1

  • swap [交换函数]
  • reverse [sort倒转]
  • erase [删除一段数组,经常和下面的unique函数一起用于离散化]

//a.erase(unique(a.begin(),a.end()),a.end()) 离散化去重复

  • unique [见上]
  • nth_element [快选,第k个大的数是什么,时间复杂度为O(n),内部实现方式和快排差不多,具体不知道emmm]
  • memset [初始化,0x3f大于10^9]
  • memcpy??????????

vector

vector<int> b{1,2,3,4};
//vector存图,如邻接表(???)
//两个vector可以按字典序排序

string

string a,b,c;
a.size();
a.length();//返回长度
a=b+c;
a+="xqy";
a+='s';
a+='d';
a="8*ying is my wife";
cout<<a.substr(0,6);//输出为8*ying
//printf不能直接输出string【string是个指针,乱码】,但是后面加一个东西c_*******???可以输出
strstr();//是否存在一个子串

set

set<int >s;
multiset<int>;
//其中的erase很神奇会把所有的***都删掉???????
//内部是个红黑树/平衡树,很长很长emmm
if(s.count(x))
auto i=s.lower_bound(x);//返回大于x的最小值
auto j=s.upper_bound(x);//返回大于等于x的最小数

map

//如果map里的位置没东西就会返回理想值,如int会返回0,string会返回""
for(auto item:M)//遍历

queue

q.push(x);
q.front();
q.pop();
q.empty();
//...没抄完就被删了

priority_queue

priority_queue<int> heap;
//时间复杂度和二叉堆一样,但常数较大

pair

pair<int,int> pair[N];
pair<int,pair<int,vector<map<pair<int,int>,set>>>>//咳咳可能对应不上,pair真是个好东西

//比较函数特别好用,先比较第一个再比较第二个,而struct需要再重载一个比较函数

unordered_set

哈希表
insert
count
size
empty

heap



[C++]那些年被虐的STL

原文地址:https://www.cnblogs.com/lsqwq/p/stl.html

时间: 2024-11-07 18:53:17

[C++]那些年被虐的STL的相关文章

STL学习思想

1.模版:一定要注意参数和返回值的模版 2.STL一系列的API:一定要注意返回值 3.容器中的都是值拷贝,而不是引用,在执行插入时,内部实行拷贝动作,所以STL中插入类时,一般都必须:无参构造函数,拷贝构造函数,重载=运算符,必须的自己重写,达到深拷贝!!! 4.一元谓词:函数只有一个参数,谓词:代表函数的返回值必须为bool类型;   二元谓词:函数只有二个参数,谓词:代表函数的返回值必须为bool类型; 5.算法和具体的数据类型相分离:通过函数对象(仿函数)来实现,本质:函数指针!!! 6

C++ STL学习——vector

学过C++的人肯定会很熟悉STL标准模板库,STL其实就是封装了一系列的接口,供我们调用.很多函数或者算法的实现不需要我们从头开始写,大大提高我们的编程效率.这篇博客在简单介绍STL的情况下,会详细的来介绍vector的使用. STL共有六大组件: 一.容器(Container):是一种数据结构,如list,vector,deque,queue等,以模板类的方法提供,为了访问容器中的数据,可以使用由容器类提供的迭代器. 二.迭代器(Iterator):提供了访问容器中对象的方法. 三.算法(Al

C++ STL中Map的按Key排序和按Value排序

原文  http://blog.csdn.net/iicy266/article/details/11906189 map是用来存放<key, value>键值对的数据结构,可以很方便快速的根据key查到相应的value.假如存储学生和其成绩(假定不存在重名,当然可以对重名加以区分),我们用map来进行存储就是个不错的选择. 我们这样定义,map<string, int>,其中学生姓名用string类型,作为Key:该学生的成绩用int类型,作为value.这样一来,我们可以根据学

stl容器区别: vector list deque set map及底层实现

在STL中基本容器有: vector.list.deque.set.map set 和map都是无序的保存元素,只能通过它提供的接口对里面的元素进行访问 set :集合, 用来判断某一个元素是不是在一个组里面,使用的比较少 map :映射,相当于字典 ,把一个值映射成另一个值,如果想创建字典的话使用它好了 底层采用的是树型结构,多数使用平衡二叉树实现 ,查找某一值是常数时间,遍历起来效果也不错, 只是每次插入值的时候,会重新构成底层的平衡二叉树,效率有一定影响. vector.list.dequ

STL vector,deque,list

一.vector可变长的动态数组必须包含头文件 #include <vector>支持随机访问迭代器• 根据下标随机访问某个元素时间为常数• 在尾部添加速度很快• 在中间插入慢所有STL算法 都能对vector操作 构造函数初始化:vector();无参构造函数, 将容器初始化成空的vector(int n);将容器初始化成有n个元素vector(int n, const T & val);假定元素类型是T, 将容器初始化成有n个元素, 每个元素的值都是valvector(iterat

C++ STL hash_map的使用以及STL hash_map的大“坑”

计算机编程中经常会用到hash表,而在C++中,使用STL编程更是少不了的.本文将介绍STL中hash_map的使用.在hash_map中使用自定义类型作为key值的方法以及在使用char *类型作为key值时遇到的问题. 一.需要的头文件以及命名空间 在linux下使用STL hash_map除了需要引用其所在头文件<hash_map>之外还要引用其命名空间.像这样写  1 using namespace __gnu_cxx; 二.hash_map的定义 先来看看hash_map是怎么定义的

c++ STL容器初探

什么是容器 首先,我们必须理解一下什么是容器,在C++ 中容器被定义为:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器.很简单,容器就是保存其它对象的对象,当然这是一个朴素的理解,这种"对象"还包含了一系列处理"其它对象"的方法,因为这些方法在程序的设计上会经常被用到,所以容器也体现了一个好处,就是"容器类是一种对特定代码重用问题的良好的解决方案". 容器还有另一个特点是容器可以自行扩展.在解决问题时

stl源码剖析 详细学习笔记 算法总览

//****************************基本算法***************************** /* stl算法总览,不在stl标准规格的sgi专属算法,都以 *加以标记 算法名称              算法用途         质变                   所在文件 accumulate          元素累计            否                   <stl_numeric.h> adjacent_differenc

stl源码剖析 详细学习笔记 算法(1)

//---------------------------15/03/27---------------------------- //算法 { /* 质变算法:会改变操作对象之值 所有的stl算法都作用在由迭代器[first,last)所标示出来的区间上.质变算法 就是 运算过程会更改区间内的元素内容 非质变算法:和质变算法相反 */ /* stl算法的一般形式 1>所有的泛型算法的前两个参数都是一对迭代器,通常称为first和last,用以标示算法的操作区间 2>stl习惯采用前闭后开区间