关于C++的一些语法以及技巧(包括STL)
Upd on 2022/1/30:初步增加STL模板库,暂未全部完成这部分内容的编写
前言
本文只讲述关于一些OI(信息学竞赛)中的实用语法,适合OIer学习,零基础或计算机专业的朋友不一定适用qwq。
如果想了解更多,或者语法查询,请移步至http://cplusplus.com。
对于OIer来说,目前CCF(中国计算机学会)对于NOI系列竞赛支持了C++11语言,然而C++最新版本为C++20,所以这里就不在介绍C++14,C++17了(建立在C++98的基础上)。
目录(也可以在侧边栏查看)
- 文件操作
- 随机数
- Sleep等待函数
- STL标准模板库
1.文件操作
关于文件操作,在 \(csp,noip\) 等竞赛中经常用到,想必大家都很熟悉了。
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
这两句话是完成文件操作的代码,它实现了对输入输出进行重定向的功能。a.in
和a.out
是文件名,r
表示只读,w
表示只写,stdin
和stdout
是系统标准输入输出,即平时的键盘输入与系统控制台的输出。
然而,在我们做小程序时,可能会思考:freopen能否关闭呢?有两个常用函数:
fclose(stdin);
fclose(stdout);
测试了一下,发现这两个函数并不能关闭freopen,重定向到键盘输入与系统控制台输出。
我们来看看真正能关闭freopen的代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
cout << a << " " << b << endl;
freopen("CON", "r", stdin);
freopen("CON", "w", stdout);
cin >> a >> b;
cout << a << " " << b << endl;
return 0;
}
其中 CON
指控制台。
2.随机数
用普通的随机数rand()
函数生成的随机数是伪随机数,是通过一个随机种子经过一个公式计算得出的。
下面这个程序我们反复运行,发现随机数是一样的。
#include <bits/stdc++.h>
using namespace std;
int main() {
for(int i = 1; i <= 5; i++) {
cout << rand() << endl;
}
return 0;
}
那么我们就要用srand()
函数来改变随机种子,最方便的方法就是拿时间当随机种子了,这样可以确保数据足够随机。
#include <bits/stdc++.h>
#include <ctime> //time使用的头文件
using namespace std;
int n = 10000;
int main() {
srand(unsigned(time(0)));//随机种子
for(int i = 1; i <= n; i++) {
cout << rand() << endl;
}
return 0;
}
但是我们发现随机数的数据相差太大,我们能不能指定一个随机数的产生范围呢?聪明的你一定想到了,对随机数取模!
#include <bits/stdc++.h>
#include <ctime>
using namespace std;
int n = 10000, s = 10;//生成n个0~s之间的随机数
int main() {
srand(unsigned(time(0)));
for(int i = 1; i <= n; i++) {
cout << rand() % s << endl;//对随机数取模
}
return 0;
}
为了确保我们的想法足够正确,我们可以把每个数出现的概率输出。
这是代码
#include <bits/stdc++.h>
#include <ctime>
using namespace std;
int a[11], n = 100000000, s = 11;
int main() {
srand(unsigned(time(0)));
for(int i = 1; i <= n; i++) {
int x = rand() % s;
a[x]++;
}
for(int i = 1; i <= s; i++) {
double k = double(a[i]) / double(n);
printf("%d出现的概率为%.2lf%%\n", i, k * 100);
}
return 0;
}
3.Sleep等待函数
Sleep等待函数可以让系统控制台等待一段时间
具体用法见代码
#include <bits/stdc++.h>
#include <windows.h>
using namespace std;
int main() {
cout<<1;
Sleep(1000);
system("cls");
cout<<2;
return 0;
}
这样可以使控制台先输出1等待1秒,再清屏再输出2。
Tip注意Sleep
的\(S\)要大写头,文件用windows.h
,Sleep函数的时间单位是毫秒
4.STL标准模板库
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。虽说它主要表出现到C++中,但在被引入C++之前该技术就已经存在了很长时间。STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
4.1.vector
不定长数组。
定义:vector<数据类型>名称
push_back(x)
:增加元素
pop_back()
:删除元素
size()
:数组大小
begin()
:指向开头元素的指针
end()
:指向结尾元素的下一个元素的指针
4.2.queue
队列,常用于BFS算法。
定义:queue<数据类型>名称
size()
:队列大小
empty()
:队列是否为空
front()
:队首元素
pop()
:删除队首元素
push(x)
:在队尾插入元素
4.3.priority_queue
优先队列,常用于最短路算法
定义:priority_queue<数据类型>名称
size()
:队列大小
empty()
:队列是否为空
* top()
:队首元素
pop()
:删除队首元素
push(x)
:在队尾插入元素
*:这里与 普通队列queue 有区别。
4.4.stack
栈,常用于DFS算法
定义:stack<数据类型>名称
size()
:栈大小
top()
:栈首元素
pop()
:删除栈首元素
push(x)
:在栈首插入元素
4.4.map
字典,顾名思义,完成类似字典的查询功能,以键-值
的方式储存,相当于下标和值都分别是自定义类型的数组。
定义:map<键数据类型,值数据类型>名称
插入的三种方式:
名称.insert(pair<键数据类型,值数据类型>(键,值));
名称.insert(map<键数据类型,值数据类型>::value_type(键,值));
-名称[键]=值
查找元素:名称.find(键)
,结果不等于名称.end()
,则找到了元素,会返回指向这个元素的指针,值可以用->second
调用,如果没找到元素,则返回名称.end()
元素的值。
- begin() 返回指向map头部的迭代器
- clear() 删除所有元素
- count() 返回指定元素出现的次数, (帮助评论区理解: 因为key值不会重复,所以只能是1 or 0)
- empty() 如果map为空则返回true
- end() 返回指向map末尾的迭代器
- equal_range() 返回特殊条目的迭代器对
- erase() 删除一个元素
- find() 查找一个元素
- get_allocator() 返回map的配置器
- insert() 插入元素
- key_comp() 返回比较元素key的函数
- lower_bound() 返回键值>=给定元素的第一个位置
- max_size() 返回可以容纳的最大元素个数
- rbegin() 返回一个指向map尾部的逆向迭代器
- rend() 返回一个指向map头部的逆向迭代器
- size() 返回map中元素的个数
- swap() 交换两个map
- upper_bound() 返回键值>给定元素的第一个位置
- value_comp() 返回比较元素value的函数
4.5 set
set 即集合,以集合的方式储存
- insert(x) 将x加入集合