【01】STL

STL


作者:abnb250/山中鹤鸣
博客:https://www.cnblogs.com/abnb250
交流群:1062464078
回到主目录点这里



mep


map及其函数:map<key, value>提供一对一的数据处理能力,第一个值被称为关键字key,每个关键字只能在map中出现一次,第二个值被称为关键字的值value,可以重复

代码模板如下:

// 定义,以 string, int 对为例
#include <map>
map<string, int> mp;             // 底层是红黑树,元素可比较大小,key 的结构体要重载 < 运算

// 2- 插入
mp.insert(make_pair("zhs", 18));       // 插入一个键值对,若原先存在该 key,则无法插入和覆盖
mp.insert(pair<string,int>("zhs", 18)); // 插入一个键值对,若原先存在该 key,则无法插入和覆盖
mp["zhs"] = 18;                        // 甚至可以类似数组下标去访问 key 对应的 value,若原先不存在该 key,则创建,若原先存在,则覆盖以前该关键字对应的值
mp.emplace("zhs", 18);                 // 插入效果跟 insert 效果完全一样

// 3- 删除
mp.erase(key);        // 删除值为 key 的元素
mp.erase(iter);       // 删除迭代器 iter 指向的元素,例如
mp.erase(mp.begin());
mp.erase(iter1, iter2); // 删除区间 [iter1, iter2) 的所有元素,例如 mp.erase(mp.begin(), mp.end());
mp.clear();           // 清空集合

// 3- 求大小
int siz = mp.size();         // 求集合大小
bool flag = mp.empty();      // 集合判空

// 4-查询
if(mp.find(key) != mp.end())          // find 函数返回一个指向被找到元素的迭代器
    cout << mp[key] << endl;
if(mp.count(key))                     // count 返回某个值元素的个数
    cout << mp[key] << endl;
auto iter = mp.lower_bound(key);      // 求 key 的下界,返回指向大于等于某值的第一个元素的迭代器
auto iter = mp.upper_bound(key);      // 求 key 的上界,返回大于某个值元素的迭代器

// 5-遍历
map<string, int>::iterator iter;      // 正向遍历
for(iter=mp.begin(); iter!=mp.end(); iter++)
{
    cout << iter->first << " " << iter->second << endl;
    // 或者
    cout << (*iter).first << " " << (*iter).second << endl;
}
map<int>::reverse_iterator riter;     // 反向遍历
for(riter=mp.rbegin(); riter!=mp.rend(); riter++)
{
    // 遍历的同时修改
    iter->second += 10;
    cout << iter->first << " " << iter->second << endl;
}
for (auto x : mp){                    // C++ 11 auto 遍历
    cout << x.first << " " << x.second << endl;
}
for (auto& x : mp){                   // C++ 11 auto 遍历
    x.second += 10;                   // 遍历并修改
    cout << x.first << " " << x.second << endl;
}

// 6- 求最值
map<string, int>::iterator it = mp.begin();     // 最小值
cout << *it << endl;
map<string, int>::iterator it = mp.end();       // 最大值
cout << *(--it) << endl;

/*
1. map 和 set 一样,其中的元素必须支持 < 运算符
2. 在插入时,使用 insert 和 用数组方式去插入,在原先存在要插入的键值
时是有区别的,insert不会插入,用数组方式插入则会直接覆盖原先数据
3. map 的迭代器支持 ++、--、==、!=、(*iter).first、
(*iter).second、iter->first、 iter->second 等操作
4. map 的迭代器不支持 +、-、 +=、 -= 等算术操作符,也不支持 >、<、
>=、<= 等比较操作符
*/


set


Set及其函数:set与map有点像,只是set只有一个值,同样自动排序。所有的操作都严格在O(logn)时间内完成。set插入的元素不能相同,而multiset可以重复。

代码模板如下:

// 1- 定义
#include <set>
set<int> s;       // 元素必须可比较大小,元素类型必须要支持 < 运算,结构体需要重载 <

// 2- 插入
s.insert(key);    // 插入

// 3- 删除
s.erase(key);     // 删除值为 key 的元素
s.erase(iter);    // 删除迭代器 iter 指向的元素,例如 s.erase(s.begin());
s.erase(iter1, iter2); // 删除区间 [iter1, iter2) 的所有元素,例如 s.erase(s.begin(), s.end());
s.clear();        // 清空集合

// 4- 求大小
int siz = s.size();       // 求集合大小
bool flag = s.empty();    // 集合判空

// 5-查询
if(s.find(key) != s.end())        // find 函数返回一个指向被查找到元素的迭代器
    cout << "exist" << endl;
if(s.count(key) == 1)             // count 返回某个值元素的个数
    cout << "exist" << endl;

set<int>::iterator iter = s.lower_bound(key);  // 求 key 的下界,返回指向大于等于某值的第一个元素的迭代器
set<int>::iterator iter = s.upper_bound(key);  // 求 key 的上界,返回大于某个值元素的迭代器

// auto 类型推断关键字 在NOI 系列比赛中也可以使用了
auto iter = s.lower_bound(key);  // 求 key 的下界,返回指向大于等于某值的第一个元素的迭代器
auto iter = s.upper_bound(key);  // 求 key 的上界,返回大于某个值元素的迭代器

// 6-遍历
set<int>::iterator iter;          // 正向遍历
for(iter=s.begin(); iter!=s.end(); iter++)
{
    cout<<*iter<<endl;
}
set<int>::reverse_iterator riter; // 反向遍历,不重要
for(riter=s.rbegin(); riter!=s.rend(); riter++)
{
    cout<<*riter<<endl;
}

// 7- 求最值
set<int>::iterator it = s.begin();  // 最小值
cout << *it << endl;
set<int>::iterator it = s.end();    // 最大值
cout << *(--it) << endl;

/*
注意:
1. set 和优先队列一样,其中的元素必须支持 < 运算符
2. set 的迭代器支持 ++、--、==、!=、*iter 等操作
3. set 的迭代器不支持 +、-、 +=、 -= 等算术操作符,也不支持 >、<、>=、<= 等比较操作符
*/


优先队列


priority_queue优先队列:堆的作用主要是用来获取最大值和最小值,因此堆有个别名叫优先队列。

常见代码模板如下:

#include <queue>
using namespace std;
// using std::priority_queue;
priority_queue<int> q;       // 定义一个空的优先队列,默认是大根堆

void test()
{

    int x = 5;
    q.push(x);           // 将 5 插入堆,这时堆顶是 5
    q.push(3);           // 将 3 插入堆,这时堆顶是 5
    q.push(2*x);         // 将 10 插入堆,这时堆顶是 10
    int k = q.top();     // 取堆顶元素,应该是 10
    q.pop();             // 删除堆顶元素,删除了 10,这时堆顶为 5
    int s = q.size();    // 求堆中元素个数,应为 2
    // 清空优先队列的一种方法
    while(!q.empty())
        q.pop();
    // 清空优先队列的第二种方法
    q = priority_queue<int>();
}

实现小根堆:

// 大根堆改成小根堆,其中 vector<Type> 为内部存储容器,
// greater<Type> 为比较方式
priority_queue<Type,vector<Type>,greater<Type>> q;

// 常为 int 类型
priority_queue<int,vector<int>,greater<int>> q;

优先队列与结构体重载运算符:

// 只能用于大根堆的结构体
struct node{
    int val;
    string info;
    ...
    // 大根堆,重载小于运算符
    bool operator <(const node& other) const {
        return val < other.val;
    }
};
// 定义一个大根堆(默认)
priority_queue<node> q;

// 只能用于小根堆的结构体
struct node{
    int val;
    string info;
    ...
    // 小根堆,重载大于运算符
    bool operator >(const node& other) const {
        return val > other.val;
    }
};
// 定义一个小根堆(默认)
priority_queue<node,vector<node>,greater<node>> q;


pair


pair:将两个变量成对组合打包在一起的数据类型,常见的应用就是保存坐标。支持比较运算符,先比较第一个元素,再比较第二个元素

pair<int,int> pos;
pos.first = 1;
pos.second = 1;
a = make_pair(1,1);
a = pair<int,int>(1,1);


vector


vector及其函数

问题 普通数组 vector 数组
定义数组 int a[N];
int a[N] = {0}; // 全初始为 0
vector<int> a;
vector<int> a(N);
vector<int> a(N, 1);// 全赋值为 1
输入元素 cin >> a[i]; cin>>t; a.push_back(t);
比较两数组相等 for(int i = 0; i < n; i++){ if(a[i] == b[i]) ...... } if(a == b)
删除最后一个元素 len--; a.pop_back();
删除下标 i 位置的元素 for(int j = i+1; j < n; j++){ a[j-1] = a[j]; } a.erase(a.begin()+i, a.begin()+i+1);
删除下标 t1~t2 的所有元素 。。。。。。 a.erase(a.begin()+t1, a.begin()+t2+1);
在下标 i 处插入一个元素 for(int j = n+1; j >= i+1; j--){ a[j] = a[j-1]; }
a[i] = t;
a.insert(a.begin()+i, t);
翻转数组 reverse(a, a+n); reverse(a.begin(), a.end());
排序 sort(a, a+n); sort(a.begin(), a.end());


字符串


字符串:常见字符串函数与reverse

// 最常用的操作
str.size();//返回字符串长度
str.length();//返回字符串长度
str.empty();//检查 str 是否为空,为空返回 1,否则返回 0
str[n];//存取 str 第 n + 1 个字符
str.at(n);//存取 str 第 n + 1 个字符 (如果溢出会抛出异常)

// 反转
reverse(str.begin(), str.end());

// 查找
str.find("ab");//返回字符串 ab 在 str 的位置
str.find("ab", 2);//在 str[2]~str[n-1] 范围内查找并返回字符串 ab 在 str 的位置
str.rfind("ab", 2);//在 str[0]~str[2] 范围内查找并返回字符串 ab 在 str 的位置
if(str.find("ab")!=string::npos)
{   cout << "下标为:" << str.find("ab"); }

// 子串
str.substr(3); // 返回 [3] 及以后的子串
str.substr(2, 4); // 返回 str[2]~str[2+(4-1)] 子串(即从[2]开始4个字符组成的字符串)
str.substring(5, 10); // 返回 str[5]~str[9] 子串(不包含结尾)

// 插入
str.insert(2, "sz");//从 [2] 位置开始添加字符串 "sz",并返回形成的新字符串
str.insert(2, "abcd", 3);//从 [2] 位置开始添加字符串 "abcd" 的前 3 个字符,并返回形成的新字符串
str.insert(2, "abcd", 1, 3);//从 [2] 位置开始添加字符串 "abcd" 的前 [2]~[2+(3-1)] 个字符,并返回形成的新字符串

// 删除
str.erase(3);//删除 [3] 及以后的字符,并返回新字符串
str.erase(3, 5);//删除从 [3] 开始的 5 个字符,并返回新字符串

// 替换
str.replace(2, 4, "sz");//返回把 [2]~[2+(4-1)] 的内容替换为 "sz" 后的新字符串
str.replace(2, 4, "abcd", 3);//返回把 [2]~[2+(4-1)] 的内容替换为 "abcd" 的前3个字符后的新字符串

// 追加
str = str + "abc";
str.push_back('a');//在 str 末尾添加字符'a'
str.append("abc");//在 str 末尾添加字符串"abc"

ASCII码值、字母大小写转换、‘0’~‘9’

// 数字转字符: 'A'(65)  'a'(97)  '0'(48)
char A = char(65);
char a = char(97);
char c = 'a' + 2;        // 'c' = 'a' + 2
char seven = '0' + 7;    // '7' = '0' + 7

// 字符转数字
int a = 'a';       // a: 97
int A = 'A';       // A: 65
int t = 't' - 'a';       // 计算字母间差值
int seven = '7' - '0';

stringstream:主要用于字符串分割,可以先用clear()以及str()将字符串读入并进行分割,再用>>把内容输出

string s;
stringstream ss;
int a, b, c;
getline(cin, s);
ss.clear();
ss.str(s);
ss >> a >> b >> c;

字典序:字典序就是以ASCII码排序,字符串是逐位比较:ab > a ,abcd > abbb。使用sort可以对字符串进行字典序排序,字符按ASCII码由小到大排列

string str = "agfdvdsgds";
sort(str.begin(),str.end());


结构体


结构体:结构体是自定义类型,它就像一个能装不同数据类型的“包裹”。当你声明一个结构体后,需要赋予这个结构体一个名字(即结构体名)。而定义具体变量时,也可以定义结构体数组。

1.结构体的声明

struct 结构体类型名{       //其中,struct是关键字,在c++中表示结构体
    数据类型 成员变量1;    //多个成员变量可以具有不同的数据类型
    数据类型 成员变量2;
    ......
};

结构体类型名 变量名; (struct 可省略)

下面是一个例子

struct student{   //student表示结构体的类型名
    string name;
    char sex;
    int age;
    float height,score;
};

student zhangsan;//声明一个student的结构体变量叫zhangsan

student a[1001];//创建结构体数组a
//a数组中的每一个元素都是一个结构体类型student的变量

我们也能同时定义结构体和变量

struct student{
    string name;
    char sex;
    int age;
    float height,score;
}a[1001];

2.结构体的使用
将结构体变量视为一个整体进行操作

swap(a[1], a[2]);

使用符号 . 对结构体变量的成员进行操作

结构体名.成员变量名

下面是一个例子

student a;//李四
cin >> a.name;//输入赋值李四的名字
a.age = 23;//直接赋值给李四的年龄为23

3.结构体初始化

student a = {"tuotuo",'F',12,168,100};

student a;
cin >> a.name >> a.sex;
a.age = 12;

4.结构体中的sort函数

struct student {
    string name;
    int age;
    float height;
}a[10];
bool cmp(student a, student b){
    return a.age < b.age;
}
int main(){
    ...//输出
    sort(a, a + n, cmp);//按照年龄从小到大排序
    ...//输出
}

数组标记和数组连续性

// 标记数组
int flag[N];  // flag[i] 用于标记状态或者计数

flag[i] = 1;  // 数组标记状态,选择 / 不选择

flag[i]++;    // 数组标记计数,记录i出现的次数

数组连续性

// 连续最长相同、最长上升或下降:相邻两项比较,并讨论即可
int a[N], s = 0;
int ans = 0;

for(int i = 1; i <= n; i++) {
    if(a[i] == a[i-1]) {  // a[i] < a[i-1] 或 a[i] > a[i-1]
        s++;
        ans = max(ans, s);
    } else {
        s = 1;
    }
}
cout << ans;


posted @ 2026-09-20 17:50  abnb250  阅读(6)  评论(0)    收藏  举报