工欲善其事必先利其器——盘点PAT中非常好用的工具(持续更新)

本文分享了C++编程中的实用技巧,包括字符处理函数、字符串转换、空格处理、二分查找及分式运算等,通过实例解析,帮助读者提高编程效率和算法优化能力。
我有的时候在刷PAT的题目的时候,做完之后去拜读大神们的代码,从中收益颇多,我觉得有必要写一个经验贴来记录我在刷题的过程中自己的一些反思和一些非常好用的譬如函数啊,技巧啊什么的,希望能够帮到大家

一. isdigital()和isalpha()

1.头文件(c++),<ctype.h>(c语言):这两个头文件中包含了一系列关于字符处理的一些函数,在处理字符串问题中,可以使用这里面的函数来简化代码。
2.这两个函数是在处理字符串问题中常用的两个函数,首先我们说isdigital()函数,参数数一个字符,如果这个字符是介于‘0’~‘9’之间的话,那么就返回一个非0值,如果不是呢,那就返回0。
3.关于isalpha()函数,输入也是一个字符,如果输入的字符是小写字母‘a’到’z’那么返回非零数字2,如果是大写字母’A’到’Z’,就返回非零数字1,不是则返回0.

#include<iostream>
#include<string>
using namespace std;
int main()
{
 string str = "0123456789abcDEF#$%^&*";
 //for (int i = 0; i < str.length(); i++)cout << isdigit(str[i]) << endl;
 for (int i = 0; i < str.length(); i++)cout << isalpha(str[i]) << endl;
 return 0;
}

4.如果是上面的for语句执行,那么输出的就是连续的10个非零数字,然后跟着的全是0,如果是下面的for语句执行,那么会发现abc对应的位置输出的是2,DEF对应的位置输出的是1,其它位置输出的是0
具体应用可以参考:
[PAT B1014/A1061]Dating
5.cctype中其他的一些函数这里就不多讲了,有兴趣的同学们可以去自己看一看,我列几个自己认为应该会有点常用的函数:
isalnum()(如果参数是字母数字,即字母或数字,该函数返回true)
islower()(如果参数是小写字母,该函数返回true)
isupper()(如果参数是大写字母,该函数返回true)
tolower()(如果参数是大写字符,则返回其小写,否则返回该参数)
toupper()(如果参数是小写字母,则返回其大写,否则返回该参数)

二. to_string()和sprintf()

1.to_string()函数支持将int,long,long long,unsigned,unsigned long,unsigned long long,float,double,long double的数据转化成对应的字符串string类型,具体用法可以看代码:

注意必须加入头文件string,否则不能使用
#include<iostream>
#include<string>
using namespace std;
int main()
{
 float pi = 3.141593;
 int perfect = 28;
 string PI = "pi is " + to_string(pi);
 string Perfect = to_string(perfect) + " is a perfect number";
 cout << PI << endl;
 cout << Perfect << endl;
 return 0;
}
/*
输出结果:
pi is 3.141593
28 is a perfect number
*/

2.sprintf()的作用与to_string()感觉有相似之处,所以我把它们放在一起比较,sprintf()比to_string()要好的一点就是,sprintf()可以将数字转换成string,并且可以将其格式化,这是to_string()办不到的,至于怎样去理解,就是把它当做printf()理解就可以了,例如
sprint(str,"%d",n)就表示把n以%d的形式写到str字符数组中。

这里我们也可以间接复习printf相关格式问题,看下面的代码,看看自己能不能解出输出
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
int main()
{
 char str[100];
 sprintf(str, "%d", 123);
 cout << str << endl;
 sprintf(str, "%8d", 123);
 cout << str << endl;
 sprintf(str, "%-8d", 123);
 cout << str << endl;
 sprintf(str, "%08d", 123);
 cout << str << endl;
 sprintf(str, "%8x", 123);
 cout << str << endl;
 sprintf(str, "%10.4f", 123.456789);
 cout << str << endl;
 return 0;
}
//输出如下:
123
     123
123
00000123
      7b
  123.4568

3.还有一个很好用的功能相同的函数就是atoi(ascii to integer)和itoa(integer to ascii)如果不是很复杂的题目,就用to_string实现int到string的转化,使用atoi或者itoa也可以实现二者之间的转化如果对格式要求较高,或者在某些特定情况下,那就要使用sprintf函数了。

三、含有空格的字符串处理-------getline()

1.今天做到了一道题,是A组的1077题,这道题是关于字符串处理的题,一开始做题的时候总是出错,后面经过自己调试之后,发现是输入的问题,因为输入的字符串中含有空格,而cin读取到空格就停止了,故自己上网搜索了相关的解决办法,发现了getline这个好用的函数
2.getline()函数的定义:

       istream& getline ( istream &is , string &str , char delim );
       istream& getline ( istream &is , string &str );

第一个参数是输入的方式,第二个参数是输入的字符串,delim表示终止符,表示读到某个特定的终止符就停止了。一般情况下delim是缺省的,故可以不加delim,缺省为\n,也就是读入到换行符的时候终止,下面举几个例子:

#include<iostream>
#include<string>
using namespace std;
int main()
{
 string str1,str2;
 getline(cin, str1);
 getline(cin, str2,'#');
 cout << str1 << endl;
 cout << str2 << endl;
 return 0;
}
/*
输入:
Clementine Lee Kenny
Clementine# Lee Kenny
输出:
Clementine Lee Kenny
Clementine
*/

可以看到第二个输出读取到#就截止了,这也就体现了getline的重载函数。
3.另外要注意的是,在A1077题中(下附链接),首先输入N的时候,必须、一定要把换行符干掉!否则你输入的第一个字符串会录不进去导致不调试的话不知道自己错在哪里了。(因为cin不会自己干掉换行符/n,那么输入N之后,直接使用getline读取的第一个就是\n,那么第一个字符就没有数值)

[PAT A1077]Kuchiguse

四、二分查找的有力工具——binary_search()

  1. 在一些特殊题中,会含有查找这个操作,相信大部分人对冒泡排序都是很熟练的,(当然对二分查找也很熟悉的大佬就当我没说),但是冒泡排序是O(N^2)级别的时间复杂度,二分查找如果不是非常熟练也会很容易出错,所以我们可以借助STL为我们提供的有力工具
  2. binary_search()返回值为bool类型,具体用法为binary_search(arr[],arr[]+size,index),在所给数组范围内寻找值为index的数,如果找到则返回true,找不到则返回false
  3. lower_bound(arr[],arr[]+size,index)和upper_bound(arr[],arr[]+size,index)函数也是非常好用的函数,lower_bound()的功能是寻找数组中第一个大于或等于index的函数,upper_bound()的功能则是寻找数组中第一个大于index的函数,返回值是寻找到元素的地址。
  4. 具体题目可见
    [PAT B1030/A1085]Perfect Sequence
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
 vector<int> v;
 for (int i = 0; i < 20; i++)v.push_back(i*i); //输入1,4,9,16......
 //这里为了偷懒已经是有序了,不需要使用sort函数了
 cout << boolalpha << binary_search(v.begin(), v.end(), 25) << endl;
 cout << boolalpha << binary_search(v.begin(), v.end(), 27) << endl;
 cout << upper_bound(v.begin(), v.end(), 25) - v.begin() << endl;
 cout << lower_bound(v.begin(), v.end(), 25) - v.begin() << endl;
 return 0;
}
//输出结果:
true
false
6
5

五、分式运算的有关函数

代码来源于《算法笔记》,仅供学习,侵删
  1. 首先,分式运算就难免有化简,而化简就要用到最大公约数,下面给出最大公约数的求解函数,这里使用的是辗转相除法,这里晴神给的代码已经很简单了,注意这里的a,b可以不分大小,如果a比b小,那么a%b=a,就相当于把a和b交换了,这里由于有可能在计算的时候有溢出,所以在原题目里面我使用的是long long型数据,这里晴神的源代码是int型的,看具体题目而定,但我建议还是使用long long型
//辗转相除法求最大公约数
long long gcd(long long a, long long b)
{
 return !b ? a : gcd(b, a%b);
}
  1. 分数的化简:这里很需要注意,便于计算,我们规定如果分数为负,那么分子为负而分母为正,也就是时时刻刻保证分母是正的,所以首先做的事就是判断分母是不是负数,如果是,那么使得分子分母同乘-1,然后再进行接下来的化简;接下来就是如果分子为0,我们就令分母为1,其实这时候分母为多少无所谓,但是为1运算起来要方便一些,出错的概率也要小;如果分子不为1,那么这时候我们就要对分式上下同除最大公约数,注意是它们的绝对值的最大公约数!
//分式的结构体
struct Fraction{
int up,int down;//分子,分母
}
//化简函数
Fraction reduction(Fraction result)
{
 if (result.down < 0) {
  result.up = -result.up;
  result.down = -result.down;
 }
 if (result.up == 0) result.down = 1;
 else {
  long long d = gcd(abs(result.up), abs(result.down));
  result.up /= d;
  result.down /= d;
 }
 return result;
}
  1. 分数的输出,这里我们就分整数,假分数,真分数三种情况讨论就行了,如果分母为1,那么表示就是整数,直接输出分子就行;如果是假分数,由于c++是向0取整,直接用f.up/f.down表示整数部分就行,c++里面取余运算不看符号,符号是与被除数相同,这点要记住
//分数的输出
void show(Fraction f) {
 f=reduction(f);
 if (f.down == 1) printf("%lld", f.up);
 else if (abs(f.up) > abs(f.down)) {
  printf("%lld %lld/%lld", f.up / f.down, abs(f.up) % f.down, f.down);
 }
 else printf("%lld/%lld", f.up, f.down);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值