zoukankan      html  css  js  c++  java
  • 【紫书学习笔记】


    //简直不能再讨厌一堆文字摆在一起的状况了,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存储即可。 
    满堂花醉三千客,一剑霜寒十四州
  • 相关阅读:
    安装DCOS,关于docker异常引发的调查
    搭建DNS服务器-bind
    DNSmasq
    桥接以及Mercury MW54R中继
    docker异常处理
    vmware的双网卡以及Pro的注册码
    ssh免密登录
    系统原生文件MD5值获取
    mysql数据库要按当天、昨天、前七日、近三十天、季度、年查询
    dirname(__FILE__) 介绍
  • 原文地址:https://www.cnblogs.com/phemiku/p/10954145.html
Copyright © 2011-2022 走看看