C++ 刷题实用方法总结

本文作者分享了准备PAT竞赛时总结的一些常用算法和函数,包括cmath头文件中的绝对值、取整、幂运算等;climits头文件中的最大最小值设定;bitset头文件中的二进制操作;进制转换函数的实现;输出格式的控制;字符串转换;algorithm头文件中的排序、查找和反转函数;以及cctype头文件中的字符类型判断。这些内容对于解决在线判题和算法竞赛中的问题非常有帮助。
摘要由CSDN通过智能技术生成

准备 PAT 竞赛时自己总结的实用函数,搞过 OJ 的应该都有一套自己总结的算法秘籍(小抄),这种东西主观性比较强,自己搞的才看的懂,发出来做个记录吧

阅读原文

cmath头文件

其针对的参数大多为double,所有进行整型判断的时候需要进行转换:(double)int;

方法含义
fabs()绝对值
floor()、ceil()向下、向上取整
pow(r, p)幂值: r p r^p rp
sqrt()开根
round()四舍五入取整
log()以e为底的对数

并没有以任意数为底的求对数函数,但可以采用换底公式: l o g a b = l o g e b / l o g e a log_ab=log_eb/log_ea logab=logeb/logea

climits头文件

最常使用的是对最大最小值的赋予: INT_MAX/MIN


    int max = INT_MIN, min = INT_MAX; //最大值初始要足够小,最小值要足够大
    cout << max << " " << min << endl;

bitset头文件

二进制操作

    bitset<5> b("11"); //5表示5个⼆进位
    // 初始化⽅式:
    // bitset<5> b; 都为0
    // bitset<5> b(u); u为unsigned int,如果u = 1,则被初始化为10000
    // bitset<5> b(s); s为字符串,如"1101" -> "10110"
    // bitset<5> b(s, pos, n); 从字符串的s[pos]开始,n位⻓度
    for (int i = 0; i < 5; i++)
        cout << b[i];
    cout << endl
         << b.any(); //b中是否存在1的⼆进制位
    cout << endl
         << b.none(); //b中不存在1吗?
    cout << endl
         << b.count(); //b中1的⼆进制位的个数
    cout << endl
         << b.size(); //b中⼆进制位的个数
    cout << endl
         << b.test(2);              //测试下标为2处是否⼆进制位为1
    b.set(4);                       //把b的下标为4处置1
    b.reset();                      //所有位归零
    b.reset(3);                     //b的下标3处归零
    b.flip();                       //b的所有⼆进制位逐位取反
    unsigned long a = b.to_ulong(); //b转换为unsigned long类型

进制转换函数

手动写法

        int len = 0, arr[100];
        do
        {
            arr[len++] = n % radix;
            n = n / radix;
        } while (n != 0); //十进制转为其他进制
        
        for (int i = len - 1; i >= 0; i--)
        {
            n = n * radix + arr[i];
        } //其他进制转为十进制

输出格式

在使用头文件时可以根据输出关键字进行进制的转换

    cout << "35的8进制:" << oct << 35 << endl;
    cout << "35的10进制" << dec << 35 << endl;
    cout << "35的16进制:" << hex << 35 << endl;
    cout << "35的2进制: " << bitset<8>(35) << endl; //<8>:表示保留8位输出
strtol()函数

任意进制转换为十进制(str→long int),其格式为: long int strtol(const char *nptr, char **endptr, int base) ,base是要转化的数的进制,非法字符会赋值给endptr,nptr是要转化的字符
因为是C语言自带的函数,所以字符串只能用char数组的方式读入(也可以字符串读入然后转换成字符数组)


    char a[20]="10549stend#12";  
    char *stop;  //建立一个由stop指向的字符数组
    int ans=strtol(a, &stop, 8);   //将八进制数1054转成十进制,后面均为非法字符
    printf("%d\n",ans);  
    printf("%s\n", stop);   

itoa()函数

十进制转换为任意进制(int→str),其格式为: charitoa(int value,charstring,int radix);,radix是要转化的数的进制
因为是C语言自带的函数,所以字符串只能用char数组的方式读入(也可以字符串读入然后转换成字符数组)

    int num = 10;  
    char str[100];  
    _itoa(num, str, 2);  //c++中一般用_itoa,用itoa也行,
    printf("%s\n", str);
sprintf()函数

也是将一个10进制数转换为指定格式的n进制字符串,函数原型: int sprintf( char *buffer, const char *format, [ argument] … )


    char s[100]={0};
    sprintf(s, "%d", 123); //十进制输出产生"123"
    sprintf(s, "%4d%4d", 123, 4567); //指定宽度不足的左边补空格,产生:" 1234567"
    sprintf(s, "%8o", 123);    //八进制输出,宽度占8个位置
    sprintf(s, "%8x", 4567); //小写16 进制,宽度占8 个位置,右对齐
    sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
    int i = 100;
    sprintf(s, "%.2f", i);    //注意这是不对的
    sprintf(s, "%.2f", (double)i);    //要按照这种方式才行

cstring头文件

函数初始化数组

给数组初始化时,可以使用memset()函数进行填充,而不用for循环遍历,其格式为: memset(数组名,初始值,sizeof(数组名));其在头文件中,只用memset()函数为数组赋0或-1时使用
也可对二维数组和多维数组进行初始操作

int arr[10];
memset(arr, 0, sizeof(arr));
for (auto i = 0; i < 10; i++)
{
    cout << arr[i] << " ";
}

字符串转换数组

字符串转换为字符数组需要使用中的strncpy方法将字符串内容挨个拷贝进数组中

字符数组转换为字符串可以直接进行赋值转换

#include <iostream>
#include <cstring>
using namespace std; 

int main()
{

    string s = "aaaa vvva";
    char a[10];
    strncpy(a, s.c_str(), s.length()); //使用<cstring>中的方法将字符串拷贝到数组中
    for (int i = 0; i < 10; i++)
        cout << a[i];
    cout << endl;

    char arr[] = "123 45sdf";
    string str = arr; //直接将数组名赋值给字符串
    cout << str << endl;
    system("pause");
    return 0;

}

tostring函数

在头文件中,也可以不用
作用是将其他类型的数据转换为string型

    string s1 = to_string(123); // 将123这个数字转成字符串
    cout << s1 << endl;
    string s2 = to_string(4.5); // 将4.5这个数字转成字符串
    cout << s2 << endl;
    cout << s1 + s2 << endl;           // 将s1和s2两个字符串拼接起来并输出
    printf("%s\n", (s1 + s2).c_str()); // 如果想⽤printf输出string,得加⼀个.c_str()

string转换成int,double可以使用stoi和stod方法,其含义为string to int,其他数据类型也适用只要将最后一个字母写成目标类型的首字母


    string str = "123";
    int a = stoi(str); //非法字符会自动去除
    cout << a << endl;
    str = "123.44";
    double b = stod(str);
    cout << b << endl;

algorithm头文件

数学函数

max(x,y)、min(x,y)函数用来返回两个数(可以是浮点)中较大或较小的那个,如果是判断三个数的最大值可以写成: max(a,max(b,c))

abs()只能是整数,浮点数可以用下的fabs()

swap()用来交换两个数的值

sort函数

sort排序函数在头文件中,主要是对数组进行排序,格式为: sort(数组头,数组尾,规则cmp);

cmd的排序规则的格式是返回一个大小判断的bool值,不能有=号,sort是不稳定的排序

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

bool cmp(int a, int b) //cmp规则的定义几乎都是这种格式
{                      // cmp函数返回的值是bool类型
    return a > b;      // 从大到小排列,不能有“=”号
}
int main()
{
    vector<int> v(10);
    for (int i = 0; i < 10; i++)
    {
        cin >> v[i];
    }
    sort(v.begin(), v.end()); // 因为这⾥没有传⼊参数cmp,所以按照默认,v从小到大排列

    int arr[10];
    for (int i = 0; i < 10; i++)
    {
        cin >> arr[i];
    }
    sort(arr, arr + 10, cmp); // arr从⼤到小排列,因为cmp函数排序规则设置从大到小
    system("pause");
    return 0;
}
struct的sort

结构体中可能会对多个变量进行比对,这就需要进行自定义的cmp函数

有一个学生结构体,要对学生进行排序时按照如下方法:当成绩不同时按从大到小排列,若成绩相同,对相同者进行学号从小到大排列

struct stu
{ // 定义⼀个结构体stu,number表示学号,score表示分数

    int number;
    int score;

}; 
bool cmp(stu a, stu b)
{                           // cmp函数,返回值是bool,传⼊的参数类型应该是结构体stu类型

    if (a.score != b.score) // 如果学生分数不同,就按照分数从大到小排列
        return a.score > b.score;
    else // 如果学生分数相同,就按照学号从小到大排列
        return a.number < b.number;

}
bool cmp(stu a, stu b)
{ //写成三目运算符

    return a.score != b.score ? a.score > b.score : a.number < b.number;

}

cmp_char[]

字符数组的排序不能像字符串那样直接进行比较,需要使用中的strcmp()函数

return (strcmp(a.name, b.name) < 0); //递增
return (strcmp(a.name, b.name) > 0); //递减 
项式cmp

PAT(advance)中的T1038中就要将字符串使用多项式相加的规则进行排序

bool cmp(string a, string b)
{

    return a + b < b + a; //如果a+b<b+a,a就在前面,否则反之

}

reverse()函数

中的反转函数,通过指针或迭代器用来反转相应范围内的数,应用于数组和字符串较多
用来反转字符串非常方便

    char arr[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
    reverse(arr, arr + 4);
    string str;
    getline(cin, str);
    reverse(str.begin(), str.end());//反转首尾
    cout << str << endl;

next_pernumtation()

当前序列的下一个全排列,可配合do…while()循环输出一个序列的全排列


    int arr[3] = {1, 2, 3};
    do //先输出本身
    {
        cout << arr[0] << " " << arr[1] << " " << arr[2] << endl; //只能使用单循环语句
    } while (next_permutation(arr, arr + 3));                     //输出最后一个序列后返回值为false

max_element()及min_element()函数

中的求最大最小值的函数,可对普通数组和vector数组进行使用
返回的是迭代器或指针,所以加上取值符*,若求下标则用返回的结果减去数组的起始位置即可

//求值
vector<int> vec;
int maxValue = *max_element(v.begin(),v.end()); 
int minValue = *min_element(v.begin(),v.end());
int maxPosition = max_element(v.begin(),v.end()) - v.begin(); 

a[]={1,2,3,4,5,6};
int maxValue = *max_element(a,a+6); 
int minValue = *min_element(a,a+6); 
int maxPosition = max_element(a,a+6) - a; 

初始化数组

memset()函数

给数组初始化时,可以使用memset()函数进行填充,而不用for循环遍历,其格式为: memset(数组名, 初始值, sizeof(数组名));其在头文件中,只用memset()函数为数组赋0或-1时使用
也可对二维数组和多维数组进行初始操作

int arr[10]; 
memset(arr, 0, sizeof(arr)); 
for (auto i = 0; i < 10; i++)
{

    cout << arr[i] << " ";

}

fill()函数

与memset不同的是可以对数组不同范围内赋予任意值,格式: fill(起,始,初始值)

    int arr[10];
    fill(arr + 2, arr + 5, 234);

find函数

find()函数的具体实用是可以返回一个数组(包括动态)中某个特定元素的指针(迭代器),因为数组的存储空间是连续的,用当前指针(迭代器)去减去开始的指针(迭代器)得到的就是数组中该元素的下标


    int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
    int a_length = sizeof(a) / a[0]; //获取数组a的长度
    vector<int> b{10, 20, 30, 40, 50};
    int *a_head = a;                                //获取起始位置
    int *a_position = find(a, a + a_length, 6);     //被查找元素的位置
    cout << a_position - a_head << endl;            //下标
    auto b_position = find(b.begin(), b.end(), 30); //动态数组返回的是迭代器类型,auto==vector<int>::iterator
    cout << b_position - b.begin() << endl;         //下标

binary_search()

用以实现二分查找: binary_search(first,last,val),直接使用find函数也可,但如果查找数组中第一个大于X的数就不好实现了,所以二分查找又延伸出边界的查找

    int a[100] = {4, 10, 11, 30, 69, 70, 96, 100};
    int b = binary_search(a, a + 9, 4); //查找成功,返回1
查找边界

lower_bound()和upper_bound()函数作用的对象是一个有序数组或容器,其格式为: lower_bound(first, last, val) ,返回数组或容器中第一个小于(或大于)val的值的位置(指针或迭代器),若获取下标用其返回的位置减去起始位置即可


    vector<int> v = {2, 5, 1, 3, 7, 6, 9, 5};
    sort(v.begin(), v.end());
    int up_position = upper_bound(v.begin(), v.end(), 6) - v.begin();
    cout << v[up_position] << endl;

    int arr[10] = {3, 5, 6, 2, 7, 9, 1, 2, 6, 8};
    sort(arr, arr + 10);
    int low_position = lower_bound(arr, arr + 10, 7) - arr - 1;
    cout << arr[low_position] << endl;

cctype头文件

就是C语言中的<ctype.h>头文件,里边包含一些类型判断函数非常方便
有时不进行头文件引用也可以进行函数的使用

    char c;
    cin >> c;
    if (isalpha(c))
    {
        cout << "c is alpha";
    }
    if (islower(c))
    {
        cout << endl
             << "islow";
    }

其他的判断函数还包括:

函数名意义
isalpha字母(包括大写、小写)
islower小写字母
isupper大写字母
isalnum字母(大写、小写)+数字
isblankspace和\t
isspacespace、\t、\r、\n

此外还有tolower和toupper方法用来将字符转换为大写或小写


    char c = 'A';
    char t = tolower(c); // 将c字符转化为⼩写字符赋值给t
    cout << t << endl;   // 此处t为'a' 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值