《算法笔记》C与C++语言相关
这是一篇学习笔记,基于胡凡主编的《算法笔记》的第二章“C/C++快速入门”。
在学习那一章的过程中,我将其中之后用的到的内容整理为这篇笔记,适合了解C和C++语言的人用于复习其语法中与做算法题相关的特性与技巧。
本文中部分内容经过顺序调整和补充,不完全按照原书内容。详细内容请看原书。
变量类型
整型
%d
为int输出格式。
%lld
为long long输出格式
- 32位或者$10^9$以内的整数:int
- 64位或者$10^{18}$以内的整数:long long。且字面量后面要加上LL后缀
浮点型
%f
为float和double的输出格式。
%lf
为double输入格式。
都用double型就好。float型只有6-7位有效精度,double型有15-16位。
字符型
%c
为char型输出格式。
%s
为char数组输出格式。
布尔型
c++中直接用,c中得添加stdbool.h
头文件。
整型常量赋值给布尔变量时0为false,非0为true。
作为整型数据输出时,true为1,false为0。
强制类型转换
1 | (新类型名)变量名//C中的转换 |
无穷大的表示
无穷大INF可以设置为int型的最大值,即$(1<<31)-1$。
但更常用$2^{30}-1$以避免相加之后溢出,它的十六进制形式:0x3fffffff
1 | const int INF = (1<<31)-1; |
条件表达式的简化
- 条件表达式为
表达式!=0
可以省略!=0
- 条件表达式为
表达式==0
时可以省略==0
并取反,即变为!表达式
常用math函数
头文件:math.h
函数 | 说明 |
---|---|
fabs(double x) | 对double变量取绝对值 |
floor(double x)、ceil(double x) | 对double变量向下取整、向上取整,但返回值为double型 |
pow(double r,double p) | 返回$r^p$ |
sqrt(double x) | 返回x的算术平方根 |
log(double x) | 返回$lnx$,需要用换底公式$\log_ab=\frac{lnb}{lna}$得到其他底数的对数 |
sin(double x)等三角函数 | |
asin(double x)等反三角函数 | |
round(double x) | 返回保留整数部分的四舍五入后的x,但返回值为double型 |
常用字符串函数
头文件:string.h
函数 | 说明 |
---|---|
strlen(字符数组) | 返回字符串长度,不含\0 |
strcmp(字符数组1,字符数组2) | 按字典序比较大小,串1大于串2返回正整数,小于则返回负整数,等于则返回0 |
strcpy(字符数组1,字符数组2) | 将字符数组2的内容复制到字符数组1,包括\0 |
strcat(字符数组1,字符数组2) | 将字符数组2接到字符数组1后面 |
数组
数组初始化
定义数组时初始化
1 | /*一维数组*/ |
若数组大小过大($10^6$级别),需要将其定义在主函数外面。
因为函数内部局部变量使用系统栈,空间较小,容易栈溢;
而函数外部全局变量使用静态存储区,空间较大。
1 |
|
利用memset函数初始化
头文件:string.h
用于给某个范围内的内存区域的每个字节赋相同的值。
1 | memset(首地址,每个字节的值,区域长度); |
由于0的补码为全0,-1的补码为全1,不容易赋值错误,尽量只用memset设置这两种初值,赋其他值使用fill函数。
以数组作为函数参数
- 参数中数组的第一维可以省略。但第二维以及更高维的长度不可省略。
- 数组作为参数时,对数组元素的修改等同于对原数组元素的修改。(我的理解:数组名仍然是值传递,但是复制给形参的只不过是数组首地址,根据这个首地址对数组元素寻址到的数组元素就是原本的数组元素)
浮点数比较
由于浮点数存储的误差,不能直接用==
来比较两个浮点数是否相等,需要用一个极小数eps来修正。
1 | const double eps = 1e-8;//10^-8 |
复杂度
一般的OJ系统一秒运算次数约为$10^7-10^8$.
因此$O(n^2)$的复杂度在n=1000时是可以承受的($10^6$级别),n=100000时是不可承受的($10^{10}$级别)
指针
1 | int *p1,p2;//注意:p1为int*,但p2为int |
- 指针是一个unsigned类型的整数。
- 指针变量可以进行加法,对
int*p
来说,p+1代表下一个int型变量地址。支持自增操作。 - 指针变量可以进行减法,减法结果是两个地址偏移的距离,距离以指针的基类型为单位。支持自减操作。
指针与数组
数组名称可作为数组首地址使用,即对于int数组a:a==&a[0]
,a+i==&a[i]
,*(a+i)==a[i]
1 | int a[10]={0}; |
引用
用于产生变量的别名,无法对常量使用。在函数参数类型后加上&
,这样就可以将形参作为实参的别名,对形参的修改可以影响到实参。
这是c++的语法,c中会报错。
1 | void change(int &x) { |
指针的引用:
1 | void swap(int* &p1,int* &p2) |
结构体
定义
1 | //定义举例 |
初始化
构造函数
使用构造函数(C++才有,C没有)。默认会生成无参构造函数,但如果自己定义了,那么就不会生成默认的无参构造函数。构造函数可以重载。
1 | struct student{ |
或者用简化版:
1 | struct student{ |
初始化列表
1 | struct student { |
复制
可以直接用=
复制相同类型的结构体变量,C和C++均可。但是这种方式是浅拷贝,对指针成员只复制地址,不复制指向的内容。
1 |
|
输入输出
scanf输入
1 | scanf("格式控制串",变量地址);//变量前记得加&取地址,数组名称本身就是地址 |
scanf的返回值为成功赋值的变量个数,如果遇到错误或者EOF,则返回值为EOF
printf输出
double输入用 %lf,输出用%f。
助记:读进来的时候要严格一些,需要知道你是double还是float,但是输出的时候没那么严格,因为可以隐式转换。就像小区保安需要你刷卡进小区,但是出小区时不管你是不是住户,直接给你开门就行。
默认输出6位小数,不足六位以 0 补齐,超过六位按四舍五入截断
1 |
|
实用输出格式:
输出格式 | 说明 |
---|---|
%md | 使不足m位的int变量以m位右对齐输出,高位空格补齐。超过m位保持不变。 |
%0md | 同%md,只不过高位用0补齐而不是空格 |
%.mf | 让浮点数保留m位小数输出,四舍六入五成双,“保留m位小数”用这个即可。不考虑怎么舍入 |
getchar和putchar
分别为输入和输出单个字符,可接收换行符。
1 | char c; |
gets和puts
分别为输入和输出一行字符串,并存放在一维数组中。
puts输出时自带换行。
1 |
|
输出:
1 | abc |
gets以换行符结束,不同于scanf以空白符结束,所以可以读入带空格的字符。
因此scanf完一个整数后,如果要使用gets,需要先用getchar接收整数后的换行符。
gets与scanf都会自动在读入的字符串末尾添加\0
sscanf和sprintf
头文件:string.h
即在scanf和printf前面再加一个字符数组参数,输入输出的源头与目的就变成了该字符数组,用法同scanf和printf
cin和cout
头文件:iostream
命名空间:std
C++输入输出函数,速度比不上scanf和printf,在算法题中一般不用。
1 | cin>>n>>c>>a>>b;//可以连续读入多个变量,无需指定类型 |
1 | cout<<a<<b<<c<<d<<endl;//可以连续输出多个变量,无需指定类型。endl表示换行 |