zoukankan      html  css  js  c++  java
  • 『嗨威说』算法设计与分析

    本文索引目录

    一、编码规范的选择与养成

    二、《数学之美》

    三、本学期算法学习的计划安排

    一、编码规范的选择与养成:

      与搭档可欣达成共识,在接下来的算法学习和团队制作过程中,遵循以下编码规范:

        https://www.cnblogs.com/linuxAndMcu/p/11303688.html

      并根据阅读筛选合适的编码规则如下:

      (1)版权和版本的声明:

      版权和版本的声明位于头文件的开头,主要内容有:

    1)版权信息;

    2)文件名称,标识符,摘要;

    3)当前版本号,作者/修改者,完成日期;

    4)版本历史信息;

    /*
    
    * Copyright (c) 2019,google
    
    * All rights reserved.
    
    * 
    
    * 文件名称:fileName.h
    
    * 摘 要:简要描述本文件的功能和用法
    
    * 
    
    * 当前版本:1.1
    
    * 作 者:输入作者(或修改者)名字(薛海威 张可欣)
    
    * 完成日期:2019 年 9 月 2 日
    
    * 
    
    * 取代版本:1.0
    
    * 原作者 :输入原作者(或修改者)名字 (嗨威)
    
    * 完成日期:2019 年 9 月 3 日
    
    */

      (2)头文件的结构:

      【规则 001】用 #include <filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。

      【规则 002】用 #include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。

      (3)制表位:

      【规则 003】只使用空格,每次缩进 4 个空格,即一个Tab。

      (4)空行:

      空行起着分隔程序段落的作用。空行得体(不过多也不过少)能将使程序的布局更加清晰。空行不会浪费内存,虽然打印含有空行的程序是会多消耗一些纸张,但是值得。所以不要舍不得用空行。

      【规则 004】在每个类声明之后、每个函数定义结束之后都要加空行。

      【规则 005】在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。

      【规则 006】 一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便写注释。

      【规则 007】 if、for、while、do 等语句自占一行,执行语句不得紧跟其后。 

      【规则 008】关键字之后要留空格。像 if、for、while 等关键字之后应留一个空格再跟左括号 ‘(’,以突出关键字。

      【规则 009】函数名之后不要留空格,紧跟左括号 ‘(’,以与关键字区别。

      【规则 010】‘,’ 之后要留空格,如 fun(x, y, z)。如果 ‘;’ 不是一行的结束符号,其后要留空格,如 for (initialization; condition; update)。

      【规则 011】赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如 “=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”、“^” 等二元操作符的前后要加上空格。

      【规则 012】一元操作符如 “!”、“~”、“++”、“--”、“&”(地址运算符)等前后不加空格。

      【规则 013】像 “[]”、“.”、“->” 这类操作符前后不加空格。

    void fun(int x, int y, int z); // 良好的风格
    
    void fun (int x,int y,int z); // 不良的风格
    
    
    
    if ((a>=b) && (c<=d)) // 良好的风格
    
    if(a>=b&&c<=d) // 不良的风格
    
    
    
    for (i=0; i<10; i++) // 良好的风格
    
    for(i=0;i<10;i++) // 不良的风格
    
    for (i = 0; i < 10; i ++) // 过多的空格
    
    
    
    array[5] = 0; // 不要写成 array [ 5 ] = 0;
    
    a.Function(); // 不要写成 a . Function();
    
    b->Function(); // 不要写成 b -> Function();    

      

      (5)对齐

      【规则 014】程序的分界符 ‘{’ 和 ‘}’ 应独占一行并且位于同一列,同时与引用它们的语句左对齐。

      【规则 015】{ } 之内的代码块在 ‘{’ 右边缩进后再左对齐。

    // 良好的风格
    
    void function(int x)
    
    {
    
        doSomething();
    
        other();
    
    }
    
    
    
    // 不良的风格
    
    void function(int x) {
    
        doSomething();
    
        other();
    
    }

      

      (6)命名规则:

      【规则 016】标识符应当直观且可以拼读,可望文知意,不必进行 “解码”。

      标识符最好采用英文单词或其组合,便于记忆和阅读。切忌使用汉语拼音来命名。程序中的英文单词一般不会太复杂,用词应当准确。例如不要把 CurrentValue 写成 NowValue。

      【规则 017】命名规则尽量与所采用的操作系统或开发工具的风格保持一致。

      例如 Windows 应用程序的标识符通常采用 “大小写” 混排的方式,如 addChild。而 Unix 应用程序的标识符通常采用 “小写加下划线” 的方式,如 add_child。别把这两类风格混在一起用。

      【规则 018】程序中不要出现仅靠大小写区分的相似的标识符。

    int x, X; // 变量 x 与 X 容易混淆
    
    
    
    void foo(int x); // 函数 foo 与 FOO 容易混淆
    
    void FOO(float x);

      【规则 019】程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但会使人误解。

      【规则 020】变量的名字应当使用“名词”或者“形容词+名词”。

    float value;
    
    float oldValue;
    
    float newValue;

      【规则 021】函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。

    drawBox(); // 普通函数
    
    box->draw(); // 类的成员函数

      【规则 022】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

    int minValue;
    
    int maxValue;
    
    
    
    int SetValue(…);
    
    int GetValue(…);

      【规则 023】尽量避免名字中出现数字编号,如 Value1,Value2 等,除非逻辑上的确需要编号。这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。

      【规则 024】除非缩写放到项目外也非常明确,否则不要使用缩写。

    // 良好的风格
    
    int num_dns_connections; // Most people know what "DNS" stands for
    
    int price_count_reader; // OK, price count. Makes sense
    
    
    
    // 不良的风格
    
    int wgc_connections; // Only your group knows what this stands for
    
    int pc_reader; // Lots of things can be abbreviated "pc"

      【规则 025】文件命名使用 “小驼峰命名法”,除第一个单词之外,其他单词首字母大写。

    lockScreenW.h
    
    changePasswdW.cpp

      【规则 026】结构体、类型定义( typedef)、枚举等所有类型,均使用 “大驼峰命名法”,所有单词首字母大写。

      【规则 027】无论是宏常量还是普通常量的命名,都全用大写的字母,用下划线分割单词。

      【规则 028】如果不得已需要全局变量,则使全局变量加前缀 g_(表示global),即 “匈牙利+小驼峰命名法”。

      

      (7)语法比较规范:

      【规则 029】不可将布尔变量直接与 TRUE、FALSE 或者 1、0 进行比较。

    // 良好的风格
    
    if (flag) // 表示 flag 为真
    
    if (!flag) // 表示 flag 为假
    
        
    
    // 不良的风格
    
    if (flag == TRUE)
    
    if (flag == 1 )
    
    if (flag == FALSE)
    
    if (flag == 0)

      【规则 030】整型变量与零值比较。

    // 良好的风格
    
    if (value == 0)
    
    if (value != 0)
    
        
    
    // 不良的风格
    
    if (value) // 会让人误解 value 是布尔变量
    
    if (!value)

      【规则 031】不可将浮点变量用 “==” 或 “!=” 与任何数字比较。

    // 良好的风格
    
    if ((f>=-EPSINON) && (f<=EPSINON)) // EPSINON 是允许的误差(即精度)
    
        
    
    // 不良的风格
    
    if (f == 0.0) // 隐含错误的比较

      (8)参数规范:

      【规则 032】参数命名要恰当,顺序要合理。

      例如编写字符串拷贝函数 stringCopy,它有两个参数。如果把参数名字起为str1 和 str2,例如 :

      void stringCopy(char *str1, char *str2);

      那么我们很难搞清楚究竟是把 str1 拷贝到 str2 中,还是刚好倒过来。可以把参数名字起得更有意义,如叫 strSource 和 strDest。这样从名字上就可以看出应该把 strSource 拷贝到 strDest。

      还有一个问题,这两个参数那一个该在前那一个该在后?参数的顺序要遵循程序员的习惯。一般地,应将目的参数放在前面,源参数放在后面。 如果将函数声明为:

      void stringCopy(char *strSource, char *strDest);

      别人在使用时可能会不假思索地写成如下形式:

      char str[20];

      StringCopy(str, “Hello World”); // 错误,参数顺序颠倒了

      【规则 033】如果参数是指针,且仅作输入用,则应在类型前加 const,以防止该指针在函数体内被意外修改。

      void stringCopy(char *strDest,const char *strSource);

      【规则 034】如果输入参数以值传递的方式传递对象,则宜改用 “const &” 方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。

      【规则 035】避免函数有太多的参数,参数个数尽量控制在 5 个以内。如果参数太多,在使用时容易将参数类型或顺序搞错。

     

      (9)函数功能设计:

      【规则 036】函数的功能要单一,不要设计多用途的函数。

      【规则 037】函数体的规模要小,尽量控制在 50 行代码之内。

      【规则 038】尽量避免函数带有“记忆”功能。相同的输入应当产生相同的输出。

      带有“记忆”功能的函数,其行为可能是不可预测的,因为它的行为可能取决于某种“记忆状态”。这样的函数既不易理解又不利于测试和维护。在 C/C++语言中,函数的 static 局部变量是函数的“记忆”存储器。建议尽量少用 static局部变量,除非必需。

      【规则 039】不仅要检查输入参数的有效性,还要检查通过其它途径进入

      函数体内的变量的有效性,例如全局变量、文件句柄等。

      (10)注释:

      C++语言中,程序块的注释常采用 “/*…*/”,行注释一般采用 “//…”。注释通常用于:

    (1)版本、版权声明;

    (2)函数接口说明;

    (3)重要的代码行或段落提示。

      虽然注释有助于理解代码,但注意不可过多地使用注释。

      【规则 040】每个类的定义要添加描述类的功能和用法的注释。

      【规则 041】函数声明处的注释,只描述函数功能及用法,而不会描述函数如何实现,因为那是定义部分的事情。

      void setAge(int age); // 设置学生年龄

      【规则 042】每个函数定义时要以注释说明函数功能和实现要点,如使用的漂亮代码、实现的简要步骤、如此实现的理由等等。

      (11)引用参数/预处理宏/其他:

      【规则 043】按引用传递的参数必须加上 const。

      void Foo(const string &in, string *out);

      事实上这是一个硬性约定:输入参数为值或常数引用,输出参数为指针;输入参数可以是常数指针,但不能使用非常数引用形参。

      【规则 044】使用宏时要谨慎,尽量以内联函数、枚举和常量代替之。

      宏意味着你和编译器看到的代码是不同的, 因此可能导致异常行为, 尤其是当宏存在于全局作用域中。

      值得庆幸的是, C++ 中,宏不像C中那么必要。宏内联效率关键代码可以用内联函数替代; 宏存储常量可以 const 变量替代; 宏“缩写”长变量名可以引用替代;

      【规则 045】整数用0,实数用0.0,指针用NULL,字符(串)用''。

      【规则 046】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

      【规则 047】动态内存的申请与释放必须配对,防止内存泄漏。

      【规则 048】用 free 或 delete 释放了内存之后,立即将指针设置为 NULL,防止产生 “野指针”。

      (11)一些有益的建议:

      【规则 049】当心那些视觉上不易分辨的操作符发生书写错误。

      我们经常会把 “==” 误写成 “=”,象 “||”、“&&”、“<=”、“>=” 这类符号也很容易发生 “丢 1” 失误。然而编译器却不一定能自动指出这类错误。

      【规则 050】变量(指针、数组)被创建之后应当及时把它们初始化,以防止把未被初始化的变量当成右值使用。

    【规则 051】当心数据类型转换发生错误。尽量使用显式的数据类型转换(让人们知道发生了什么事),避免让编译器轻悄悄地进行隐式的数据类型转换。

    【规则 052】当心变量发生上溢或下溢,数组的下标越界。

    【规则 053】当心忘记编写错误处理程序,当心错误处理程序本身有误。

    【规则 054】如果原有的代码质量比较好,尽量复用它。但是不要修补很差劲的代码,应当重新编写。

    【规则 055】尽量使用标准库函数,不要“发明”已经存在的库函数。

    【规则 056】尽量不要使用与具体硬件或软件环境关系密切的变量。

    【规则 057】把编译器的选择项设置为最严格状态。

     二、《数学之美》:

      前几天的算法课上,讲师分享了《数学之美》这本书,从中我倒是学到不少的思维经验,令我意外并欣喜的是,这本书里边的数学内容并不晦涩难懂,而且作者为了讲述数学之美而搭配的一些工程实例都是和我学习并感兴趣的模式识别,目标分类相关算法相关联的。这让我觉得捡到了意外的宝藏。从中有一些很有趣的东西可以分享一下如:

      1、字母可以看为是一维编码,而汉字可以看为二维编码。

      2、训练数据通常是越多越好,通过平滑过渡的方法可以解决零概率和很小概率的问题,毕竟在数据量多的时候概率模型的参数可以估计的比较准确。

      【第二点对于我在做自然语言处理的时候,感觉突然有一种一点通的感觉,算是一个不错的指导思路】

      3、相对熵(Kullback-Leibler Divergence)也叫交叉熵,对两个完全相同的函数,他们的相对熵为零;相对熵越大,两个函数差异越大,反之,相对熵越小,两个函数差异越小;对于概率分布或者概率密度函数,如果取值均大于零,相对熵可以度量两个随机分布的差异性。

      【相对熵在自然语言处理方面算是对我是一个蛮陌生的概念,但在之前在一些百度、谷歌一些比较官方的注解的时候,对这个概念的解释是比较晦涩难懂的,但是这本书刚刚好帮助我更好的去理解这个概念。】

      4、自然语言处理的历史——人们最先想到的方法是让计算机像人一样了解自然语言的语法,进而“读懂”自然语言,经过了十几年后,那些基于文法规律的模型却被新出现的基于统计模型轻易地打败了。基于文法规律的模型有什么问题呢?——1.人类自然语言的规则太多,“特例”也很多,要用人工完善这些特例是一件工作量非常大的工作,导致这个模型的进步缓慢。2.一个简单的句子都可以分析出一个复杂的语法树,而复杂句子的语法树甚至在一张纸上也画不下,后期处理的计算量自然非常大。

      【书中还提到了自然语言处理的起源历史,揭示了人类在思考如何让机器去实现自然语言处理的思路历程,这些点点滴滴的想法对以后在摸索自然语言处理方法上都有一定的推动。】

      在一些推评中我看到一则算是蛮综合性的评价点评(参考链接见后):

      ① 学习建立解决智能问题的框架。在面对智能问题时,一般地可以考虑按以下四个步骤求解:

        1.将问题转换成数字描述;

        2.找到恰当的数学模型(目标函数);

        3.对复杂的数学模型进行简化或近似处理,以便计算;

        4.求解目标函数。(对统计模型来说,还要利用数据学习参数)

      在今天这个大数据和云计算时代,统计模型往往是解决问题的利器,因为现在我们要解决的问题很多是不确定的。从信息论的角度讲,统计模型的本质是利用信息来消除或减少不确定性。此外,摩尔定律的持续作用,让计算能力快速提高的同时,计算成本急剧降低,使得解决统计模型所需要的海量计算成为可能。

      ② 在做事上,首先追求完成,而非完美。许多时候做事失败,不是因为人不够优秀,而是做事的方法不对。一开始追求大而全的解决方案,之后长时间不能完成,最后不了了之。在工程上,应该坚持寻找简单有效的解决方案,先帮助用户解决80%的问题,再慢慢解决剩下的20%问题。

      这么做至少有两个好处:

        1.节约资源。资深工程师往往倾向于低估简单方法的有效性,而完美的方案需要花费大量的资源和时间,但可能最后的提高不多,即性价比不高;

        2.简单的方案容易解释每个步骤和方法背后的道理,这样不仅便于出了问题时查错,而且容易找到今后改进的目标。

      ③ 找到科学的工作方法很重要。人类为了实现飞行的梦想,首先想到的是模仿鸟类制作振动的翅膀,但这种方法根本不能让人飞起来。后来英国人乔治·凯利爵士通过重新审视鸟类翅膀的功能,发现了空气动力学原理,并制造了一架滑翔机,实现了人类历史上第一次载人滑翔飞行。后人从空气动力学这个科学原理出发,最终发明了现代固定翼飞机。

      在人工智能领域,也存在上述“鸟飞派”和“空气动力学派”的分别。机器翻译中,最难的问题之一是词的二义性。比如Bush一词可以是美国总统布什的名字,也可以是灌木丛。最直接想法的是告诉计算机加一条规则:“总统做宾语时,主语必须是一个人”。如果这样做的话,语法规则就多得数不清了,而且还有很多例外。

      真正简单却实用的方法是,从大量文本中找到和总统布什一起出现的词,比如美国、华盛顿、国会等等,对灌木丛也作如此处理。在翻译Bush时,看看上下文中哪类相关的词多就行了。这就巧妙地把一个人类的智能问题变成计算机擅长的计算统计问题。

      从上述例子中可以看到,所谓鸟飞派,就是指从经验出发,让计算机模仿人的思维方式,试图获得智能的做法,这个做法证明行不通。所谓空气动力学派,就是指搞清楚智能问题的本质,让计算机通过数据和数学模型解决智能问题。今天人工智能的全部进步,都是走后一条道路的结果。

      《数学之美》一书,即使对不做研究或工程的人来说,也是开卷有益的。当吴军老师如讲故事般地,把复杂的问题以简单的数学形式讲述出来的时候,你会发现,原本深奥的公式是如此亲切和栩栩如生,也让人由此坚信,任何复杂的问题,最终都可以用简单的方式去解决。

    三、本学期算法学习的计划安排:

      通过长期对基础的学习,稳固算法根基知识,力求做一个更好的ACMer,在接下来的算法学习过程种,希望在大二结束的时候实现:个性化推荐学习软件

      可能用到的算法或数据结构:

      (1)应用文件存储方法,高效存取大型知识库。

      (2)知识点关键词查找算法。

      (3)学习艾宾浩斯记忆曲线,根据核心公式实现知识点的个性化推荐。

    《数学之美》推评参考链接:http://www.simayi.net/duhougan/13509.html

    如有不合理的地方,请及时指正,我愿听取改正~

  • 相关阅读:
    Compression algorithm (deflate)
    tcpip数据包编码解析(chunk and gzip)_space of Jialy_百度空间
    What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
    gzip压缩算法: gzip 所使用压缩算法的基本原理
    Decompressing a GZip Stream with Zlib
    Frequently Asked Questions about zlib
    how to decompress gzip stream with zlib
    自己动手写web服务器四(web服务器是如何通过压缩数据,web服务器的gzip模块的实现)
    What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
    C语言抓http gzip包并解压 失败 C/C++ ChinaUnix.net
  • 原文地址:https://www.cnblogs.com/WinniyGD/p/11441752.html
Copyright © 2011-2022 走看看