『嗨威说』算法设计与分析 - 第一章作业整理(编码规范 / 数学之美 / 未来计划)

本文索引目录

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

二、《数学之美》

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

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

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

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

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

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

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

1)版权信息;

扫描二维码关注公众号,回复: 7153531 查看本文章

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,字符(串)用'\0'。

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

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

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

  (11)一些有益的建议:

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

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

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

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

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

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

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

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

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

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

 二、《数学之美》:

  前几天的算法课上,讲师分享了《数学之美》这本书,从中我倒是学到不少的思维经验:

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

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

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

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

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

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

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

  这么做至少有两个好处:

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

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

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

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

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

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

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

  可以说,数学之美,也是化繁为简之美

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

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

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

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

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

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

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

猜你喜欢

转载自www.cnblogs.com/WinniyGD/p/11441752.html