【紫书学习笔记】


//简直不能再讨厌一堆文字摆在一起的状况了,so……我爱引用(huaji

※循环

  • 程序2-2 7744问题
1 #include<stdio.h>
#include<math.h>
int main()
{
for(int a = 1; a <= 9; a++)
for(int b = 0; b <= 9; b++)
{
int n = a*1100 + b*11; //这里才开始使用n,因此在这里定义n
int m = floor(sqrt(n) + 0.5);
if(m*m == n) printf("%d ", n);
}
return 0; }

读者可能会问:可不可以这样写?if(sqrt(n)== floor(sqrt(n)))printf("%d ",n),即直接判断sqrt(n)是否为整数。理论上当然没 问题,但这样写不保险,因为浮点数的运算(和函数)有可能存在误差。 假设在经过大量计算后,由于误差的影响,整数1变成了0.9999999999,floor的结果会 是0而不是1。为了减小误差的影响,一般改成四舍五入,即floor(x+0.5)。如果难以理 解,可以想象成在数轴上把一个单位区间往左移动0.5个单位的距离。floor(x)等于1的区间 为[1,2),而floor(x+0.5)等于1的区间为[0.5,1.5)。

提示2-7:浮点运算可能存在误差。在进行浮点数比较时,应考虑到浮点误差。 另一个思路是枚举平方根x,从而避免开平方操作。 

  • continue和break语句。continue是指跳回for循环的开始,执行调整语 句并判断循环条件(即“直接进行下一次循环”),而break是指直接跳出循环。

※结构体

↓结构体Point中定义了一个函数,函数名也叫Point,但 是没有返回值。这样的函数称为构造函数(ctor)。

构造函数是在声明变量时调用的,例如,声明Pointa,b(1,2)时,分别调用了Point( )和Point(1,2)。

注意这个构造函数 的两个参数后面都有“=0”字样,其中0为默认值。也就是说,如果没有指明这两个参数的值,就按0处理,因此Point( )相当于Point(0,0)。

“:x(x),y(y)”则是一个简单的写 法,表示“把成员变量x初始化为参数x,成员变量y初始化为参数y”

也可以写成:Point(intx=0,inty=0){this->x=x;this->y=y;}

这里的“this”是指向当前对象的指针。this->x的意思是“当前对象的成员变量x”,即 (*this).x

#include<iostream> using namespace std;
struct Point
 {  
int x, y;
Point(int x=0, int y=0):x(x),y(y) {} //这句话是要构造函数并初始化成员
}; Point
operator + (const Point& A, const Point& B) { return Point(A.x+B.x, A.y+B.y);
} ostream
& operator << (ostream &out, const Point& p) { out << "(" << p.x << "," << p.y << ")"; return out; } int main() { Point a, b(1,2); a.x = 3; cout << a+b << " "; return 0; }

提示5-10:在C++结构体的成员函数中,this是指向当前对象的指针。

提示5-9:C++中的函数(不只是构造函数)参数可以拥有默认值。

 ※时间相关

#include<stdio.h>
#include<time.h>
int main()
{
const int MOD = 1000000;
int n, S = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
int factorial = 1;
for(int j = 1; j <= i; j++)
factorial = (factorial * j % MOD);
S = (S + factorial) % MOD;
}
printf("%d
", S);
printf("Time used = %.2f
", (double)clock() / CLOCKS_PER_SEC);  //计时器
return 0;
}

上面的程序再次使用到了常量定义,好处是可以在程序中使用代号MOD而不是常数 1000000,改善了程序的可读性,也方便修改(假设题目改成求末5位正整数之积)。 这个程序真正的特别之处在于计时函数clock()的使用。该函数返回程序目前为止运行 的时间。这样,在程序结束之前调用此函数,便可获得整个程序的运行时间。这个时间除以 常数CLOCKS_PER_SEC之后得到的值以“秒”为单位。

提示2-17:可以使用time.h和clock()函数获得程序运行时间。常数 CLOCKS_PER_SEC和操作系统相关,请不要直接使用clock()的返回值,而应总是除以 CLOCKS_PER_SEC。

【其后的相关技巧请阅读原文】

按Enter键后,系统瞬间输出了答案820313。但是,输出的Time used居然不是 0!其原因在于,键盘输入的时间也被计算在内——这的确是程序启动之后才进行的。为了 避免输入数据的时间影响测试结果,可使用一种称为“管道”的小技巧:在Windows命令行下 执行echo 20|abc,操作系统会自动把20输入,其中abc是程序名。如果不知道如何操作命令 行,请参考附录A。笔者建议每个读者都熟悉命令行操作,包括Windows和Linux。

※输入的究极の奥义

当使用while(scanf("%d", &x) == 1)时,按Enter键,但未显示结果。

难道程序速度太慢? 其实程序正在等待输入。还记得scanf的输入格式吗?空格、Tab和回车符都是无关紧要的, 所以按Enter键并不意味着输入的结束。那如何才能告诉程序输入结束了呢? 提示2-19:在Windows下,输入完毕后先按Enter键,再按Ctrl+Z键,最后再按Enter 键,即可结束输入。在Linux下,输入完毕后按Ctrl+D键即可结束输入。

 1 程序2-10 数据统计(重定向版)
 2 #define LOCAL
 3 #include<stdio.h>
 4 #define INF 1000000000
 5 int main()
 6 {
 7 #ifdef LOCAL
 8 freopen("data.in", "r", stdin);
 9 freopen("data.out", "w", stdout);
10 #endif
11 int x, n = 0, min = INF, max = -INF, s = 0;
12 while(scanf("%d", &x) == 1)
13 {
14 s += x;
15 if(x < min) min = x;
16 if(x > max) max = x;
17 /*
18 printf("x = %d, min = %d, max = %d
", x, min, max);
19 */
20 n++;
21 }
22 printf("%d %d %.3f
", min, max, (double)s/n);
23 return 0;
24 }

这是一份典型的比赛代码,包含了几个特殊之处: 重定向的部分被写在了#ifdef和#endif中。其含义是:只有定义了符号LOCAL,才编译两 条freopen语句。 输出中间结果的printf语句写在了注释中——它在最后版本的程序中不应该出现,但是又 舍不得删除它(万一发现了新的bug,需要再次用它输出中间信息)。将其注释的好处 是:一旦需要时,把注释符去掉即可。 上面的代码在程序首部就定义了符号LOCAL,因此在本机测试时使用重定向方式读写文 件。如果比赛要求读写标准输入输出,只需在提交之前删除#defineLOCAL即可。一个更好的 方法是在编译选项而不是程序里定义这个LOCAL符号(不知道如何在编译选项里定义符号的 读者请参考附录A),这样,提交之前不需要修改程序,进一步降低了出错的可能。 提示2-23:在算法竞赛中,有经验的选手往往会使用条件编译指令并且将重要的测试 语句注释掉而非删除。

※vector

vector就是一个不定长数组。不仅如此,它把一些常用操作“封装”在了vector类型内部。
例如,若a是一个vector,可以用a.size( )读取它的大小,a.resize( )改变大小,a.push_back( )向
尾部添加元素,a.pop_back( )删除最后一个元素。

※others

  • 滥用“++”、“—”、“+=”等可以修改变量值的运算符很容易带来隐蔽的错误。建议每条语句最多只用一次这种运算符,并且所修改的变量在整条语句中只出现一次。当嵌套的两个代码块中有同名变量时,内层的变量会屏蔽外层变量,有时 会引起十分隐蔽的错误。这是
  • 初学者在求解“多数据输入”的题目时常范的错误,请读者留意。这种问题通常很隐 蔽,但也不是发现不了:对于这个例子来说,编译时加一个-Wall就会看到一条警告: warning:unused variable 's' [-Wunused-variable](警告:没有用过的变量's')。
  •  "a[n++]=x"表示首先赋值a[n]=x,然后执行n=n+1。(相当于“{a[n]=x;n=n+1;}”)
  •  简单地说,只有在放外面时,数组a才可以开得很大;放在main函数内时,数组稍大就会异常退出。
  • 如果要从数组a复 制k个元素到数组b,可以这样做:memcpy(b,a,sizeof(int)*k)。当然,如果数组a和b 都是浮点型的,复制时要写成“memcpy(b,a,sizeof(double)*k)”。另外需要注意的是, 使用memcpy函数要包含头文件string.h。如果需要把数组a全部复制到数组b中,可以写得简单 一些:memcpy(b,a,sizeof(a))。
  • 尽量用const关键字声明常数。
  • aabb这个变量用另外一个变量n=a *1100+b *11存储即可。 
满堂花醉三千客,一剑霜寒十四州
原文地址:https://www.cnblogs.com/phemiku/p/10954145.html