c++中一些头文件里暗藏的奇技淫巧

前言

c++的奥秘无穷,和数学一样,永远值得我们去研究.
我也只能略举一二,如果这对你没有什么用处,请点击右上角的那个 × .

具体内容

我先打个备注:
如果你发现你的c++使用了这些函数以后CE报错,那可能是你没有开c++11.有一些函数是在c++11里面出现的.

cctype

这个头文件看似大部分是判断字符类型的内容,但是据说比直接写要快..
你要说这个算奇技淫巧我觉得也不算,但是这些真的很好用.
比较常用的几个是这些:
isalpha(c) 判断字符 c 是否是字母.
isupper(c) 判断字符 c 是否是大写字母.
islower(c) 判断字符 c 是否是小写字母.
isdigit(c) 判断字符 c 是否是数字字符.
isspace(c) 判断字符 c 是否是空格,换行符或者tab.
这样只需要7个字母,你就可以判断一个字符是什么类型的了.
比较上原来的c>='0'&&c<='9',确实好打了很多.
我会说这是做CF的时候抢速度用的么 ?

deque

这是双端队列.它所在的头文件是<queue>.
顾名思义,它的两端都可以加入和弹出元素.
所以自然有以下的几个操作.
q.push_back(x) 在双端队列 q 的队尾加入一个元素 x .
q.push_front(x) 在双端队列 q 的队头加入一个元素 x
q.pop_back() 弹出队尾的元素.
q.pop_front() 弹出队头的元素.
q.front() 队头的元素.
q.back() 队尾的元素.
那你就说了,这些东西普通的queue也可以做到,我为什么要用双端队列呢?
我会告诉你我是为了装B单调队列吗?
你想到了吧.
我们来看看用双端队列完成的单调队列是怎么样的.
luogu p1440 求m区间内的最小值
相信大家都会写单调队列,我就不解释代码了,大家自己体会一下.

#include<bits/stdc++.h> //Ithea Myse Valgulious
} using namespace chtholly; //省略快读快写
using namespace std;
const int yuzu=2e6;
int a[yuzu|10];
deque<int> q;
int main()
{
    int i,n=read(),m=read();
    for (i=1; i<=n; ++i)
    {
        a[i]=read();
        printf("%d\n",a[q.front()]);
        for (; !q.empty()&&i-m>=q.front(); q.pop_front());
        for (; !q.empty()&&a[i]<=a[q.back()]; q.pop_back());
        q.push_back(i);
    }
}//非常漂亮的过去了.是不是很美?

string

#include<string>
虽然字符串的类型非常骚,但是常用的没这么多,所以知道那些就可以了.
不过还是有两个神技被大部分人忽略了.
第一个叫std::to_string.
这个函数能够把数字(可以是整形数,也可以是浮点数)直接转换成字符串.
真的非常好用,我们看看例题.
给出一个长度为偶数的正整数n,判断它前一半位数的数字之和是否等于后一半. n<=1e9.

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int ans=0;
    int n;
    cin>>n;
    string a=to_string(n);
    for (int i=0; i<a.size(); ++i)
    {
        if (i<a.size()/2) ans+=a[i];
        else ans-=a[i];
    }
    puts(ans==0?"Yes":"No");
}

我手打了上面的代码,大约在一分钟左右.非常快.
第二个是std::stoi.
atoi一样的是,这个函数能把string变成数字.
同理也是能变成整数或者浮点数.

要注意的是,转换的时候字符串中不能有非法字符,也不能超过数据范围,否则会当场报错.
还有这两个函数都在c++11里面.
好,我们准备下一个.

algorithm

这个头文件里骚的东西真的多.
next_permutation,prev_permutation.
这两个东西有多厉害不用我说吧,枚举全排列就靠它了.
min_element,max_element,
返回范围中最小/最大元素的迭代器.
fill(iterator first,iterator last,val)
你是不是怕memset出一些奇怪的问题?用fill!.
nth_element(it first,it nth,it last),
能让第 n 大的元素处在区间的第 n 个.
unique(it first,it last);
将区间去重(注意只能对连续相同的元素去重)并返回元素的个数的位置指向的迭代器.
所以如果要达到真实去重的效果请对区间排序.
举例:

vector<int> v={2,3,5,5,4,2,2,5};
sort(v.begin(),v.end());//v={2,2,2,3,4,5,5,5};
vector<int>::iterator it=unique(v.begin(),v.end());//v={2,3,4,5,?,?,?,?};
cout<<it-v.begin()<<endl;
for (auto i:v) cout<<i<<" ";
输出:
4
2 3 4 5 //4 5 5 5(后面是什么不重要了.) 

最后是神奇的random_shuffle,也就是随机化区间内的所有元素了.
给你的好友来上一句

#define sort random_shuffle

他会非常高兴的.(哈哈哈哈)

ctime

时间!关于日期和时间的计算在信息学竞赛中非常重要.
这一次我来介绍一下ctime中两个神奇的函数.
1:clock
这个东西可以算代码运行的时间.用法是这样的:

clock_t nowtime=clock();
...
cout<<clock()-nowtime<<endl;

这时候输出了一个数字,单位是毫秒,表示运行的时间.
这样就可以判断你是不是 t l e 了.
爆搜到时限之后直接输出 1 其实也是用的这种方法.
2.difftime
这个函数用来算两个时间之间的时间差.
用法?
首先在c++中,时间是由一个叫 t m 的结构体储存的.
这个结构体有9个成员.

struct tm{
int tm_sec;//秒
int tm_min;//分钟
int tm_hour;//小时
int tm_mday;//(这个月的)哪一天
int tm_mon;//月
int tm_year;//年(这个年是以1900作为起始时间的,设置的时候要减去1900)
int tm_wday;//星期几,0表示星期天
int tm_yday;//今年从1月1日开始的第几天
int tm_isdst;//是否是夏令时
};

然后有一个函数mktime(&t) 可以将结构体表示的时间变为秒表示的时间.
接下来用difftime函数可以算出两个日期之间差的秒数,除以 86400 就是天数.
举例计算从今年7月22日(谁的生日?) 到今天 (7月27日) 的天数.应该是5天.

int main()
{
    tm t1= {0},t2= {0};
    t1.tm_year=2018-1900,t1.tm_mon=6,t1.tm_mday=22;
    t2.tm_year=2018-1900,t2.tm_mon=6,t2.tm_mday=27;
    cout<<difftime(mktime(&t2),mktime(&t1))/86400<<endl;
}//输出5

要注意的点:
1.年份从1900开始,月份以1月为准,要减掉1;
2.计算的时间的范围在[1900,3000]之间.别过界了.
这样我们再也不怕询问时间的问题了!

stringstream

stringstream的头文件是<sstream>.
终于到压轴的神器出场了.这是我不得不对c++顶礼膜拜的原因之一.
它的适用范围很广(面对毒瘤出题人)
而我仅仅是挖开了冰山一角.
我们来看例题.
洛谷p1020 导弹拦截
这题题目不难,我们就看它的输入.
想必大家都是while (scanf("%d",&n)!=EOF){}之类的读法.
现在我们把题目改一下.
本题包含多组数据,每行一组,包含若干个数字.
这下完了.
你不给我数据组数就算了,每组数据也不给我多少个数字,我怎么读啊!
sb出题人,*************(已被屏蔽)
这题从读入上就已经干倒了一群人.
那么该怎么办呢?
考虑用getchar(),碰到空格换一个数字,碰到回车换一组数据.
非常麻烦.
那用getline,每次读入一组数据,用奇怪的方法搞来搞去.
还是很麻烦.
这时候stringstream出场了.

const int yuzu=1e5;
int a[yuzu|10],n;
int main()
{
    string s;
    for (; getline(cin,s);)
    {
        stringstream llx(s);
        n=0;
        for (; llx>>a[++n];);
    }
}

字符串流也是流的一种,可以用来输入.上题就是一种可能的方法.
那么还有一个问题也可以迎刃而解.
给出一串用奇怪符号(里面包括空格)隔开的数字,输出它们的和.
样例:

input:
{15/;; ;8787*- )),|^&&1<<>>}
output:
8803

在get字符串以后把里面不是数字的符号都变成空格,然后用stringstream输入就可以了.
配合c++11中的遍历方法和cctype头文件使得代码非常简洁.

for (char &c:s) if (!isdigit(c)) c=' ';

我不会说我们需要这个东西是因为我作死在vjudge里提交topcoder没法测样例才学的.
sstream的缺点是慢了一点,但它真的很强!

总结

c++中还有很多神奇的东西,百玩不厌.
大家看了这篇博客后也可以自己去研究研究,希望大家能够找到更好玩的东西.
那么这篇博客就到这里了,谢谢大家.

猜你喜欢

转载自blog.csdn.net/qq_31908675/article/details/81233816