深夜发现今年年初写的程序现在已经觉得丑陋异常了压根无法维护,移植到linux下时一直段错误。所以有了这篇。
//不保证以下的pascal符合规范。N久没写过了
long long ago
当时大概14年。写的pascal。对FPC只会当成TP用。不怎么懂函数。缩进是TP风格的和上一行结尾对齐。
七上的时候
15年。差不太多。丑陋的goto。但是有写很长的程序的能力了。缩进变成了两格。懂得面向过程了。六子棋就主要是这时候写的。全是拼音。这个程序因为跨越了两年多,所以风格非常不统一。
七下的时候
16年。懂得了pascal的很多高端特性。算π,五子棋,俄罗斯方块是这时候写的。(当时闲的发慌)我的第一个C++程序(Visual C++除外)就是在这个时候写的。
E1:(现在我的FFT比三年前的优美一万倍)
E2:(后期,各种模仿fpc的source,面向过程登峰造极)
八上的时候
学习了短码的C。pascal改成了C风格。同时学会了FP的4格Tab,使用另一个控制台调试,Ctrl+C,V复制粘贴,括号自动补全等等高端技巧。主要写了一些小程序,改进了connect5(现在蒟蒻的我已经打不过它了)。另外Lazarus入门。那时的pascal风格保持至今。开始转C,在CodeVS上的提交pascal和C平分秋色。
八下的时候
从(pascal+C)尝试转C++的过渡态选手,提交总是使用C++尽管遇到了各种问题。当时的C++就是用pascal直译的标准的C(连STL都不会)(UPD:现在发现记忆错误,那时的C++风格一直保持到停课前,并且已经会STL了)。pascal近乎完美,看起来和那些source一模一样,学会使用windows单元。当时是CodeVS的忠实用户,现在这个网站都打不开了,所以C++代码记录一去不复返。(10.08UPD:现在能打开了,刷新了很多认知。)
九上的时候
基本掌握了C+STL这门语言。还是pascal直译水平。任何涉及GUI的程序都仍然是pascal写的,在OI方面成为了C+STL选手。
(下面的大概是缺省源的地位,尽管当时不会用缺省源。)
九下的时候
变化很大。
第一步:使用bits库,大幅增加编译时间; -Wall (2018.3)
第二步:基本会用C++11 (2018.4)
第三步:使用局部变量 (2018.4)
第四步:精通C++11(我现在不会写C++了)(2018.5-6)
第五步:封装。连Dinic也是 (2018.5-6)
第六步:for循环中也使用局部变量 (2018.7)
越来越像真正的C++选手
高一上
和当前风格没什么区别,除了使用#define int64 long long等各种define;还没有使用C++17结构化绑定的习惯;没有(a*=b)%=mod
的习惯之外。
当前的风格
现在好像保持基本稳定了。除了Qt带来了PascalCase变成camelCase并且彻底弃用了pascal。偶尔使用C++17。
Pascal : 它死了
使用extended。函数名PascalCase。喜欢graph甚于windows。C++风格缩进(begin、then不换行,不打空格)。多使用函数和record。C风格运算符。有着type int=longint的习惯。一般不打program。
C++
camelCase。大括号不换行。除了##(宏中)、&&、||之外不打空格。越短越好。
尽量少使用#define,使用gedit的片段替代。
变量为了区分时会大写。部分全局变量会下划线开头。
万能头(偶尔改成bits/extc++.h)。
使用C风格输入输出、C风格字符数组(毕竟我是先学的C)。真的超强大。
在for比while短的绝大多数地方使用for,即使三个语句毫无干系。仅有的两个使用do-while之处是随机生成简单图和next_permutation()
。
邻接表使用vector。数组只要长度不能直觉得到就开vector。大量使用STL。sort传lambda。几乎所有图、树的题都少不了range-based for。手写的结构体、max、min、insert等等基本使用initializer_list
。哈希表使用unordered_map
(必要时重载hash)。if中声明变量。总之C++11是不可分割的一部分,能够大量简化代码。
一般会using ll=long long
,using pa=pair<int,int>
。pair是我仅有的较少使用的STL(因为太长了)。如果一定要用,我一般会使用C++17,并且使用结构化绑定,推导指引等等高端操作来代替pair<int,int>
这个冗长的词。
不使用rand()
,一般使用std::default_random_engine
。
封装一切东西。有时连最短路都封装。喜欢使用一个struct node胜过一堆数组(同时定义L(x),R(x),LCT还会有F(x))。
如果硬要我写C++98,我会这么写:
编译时一定开-Wall,-ferror-limit=3,-Wno-unused-result(linux下)。消除除了添加括号之外的所有warning(我从来不加不必要的括号)。(int)v.size()
。
下面是我的插头DP中的一段。可以看到不加括号多么简短。(位运算优先级和pascal是完全反的,+ > » > | )
能开int的尽量不开long long。几乎从不define int ll。很少inline,从不register(register在C++17中被删除了,所以本地无法编译。并且我测过,开O2时毫无卵用)
短的语句用逗号,不能用逗号时会把if换成&&和||(多年短码习惯),return换成exit。这样对于输出调试来讲特别方便,可以规避大括号,但是对于gdb来说是噩梦。比如我的输出调试中经常有这样的语句(_D
一直是调试专用的变量):
还有一个奇怪的习惯是if和for永远在同一行。
线段树、Dinic、MCMF、Kosaraju、Minimax、二分、RMQ、exgcd、计算几何等等等等全部都是刘汝佳的板子。(我不用Tarjan求SCC)FFT、FWT是两重循环。
一个C++17的例子,体现了我的一些代码风格:
高一下的更新
了解了basic_string
,并且用来替代vector的几乎所有应用。
Python
蒟蒻刚入门,没有什么风格,除了缩进用tab之外。正在努力习惯列表生成式。喜欢用lambda代替def。
为了说明python的优越性,我们可以尝试一下∑∞x=1sinxx(等于π−12)。
然而python就相当接近人类的思维习惯,并且很简短:
喜欢from numpy import *
等等各种from xxx import *
,类似于C++的using namespace std;
一个标准的main是这样的:
一般的if
和for
后如果语句很短就会写在同一行。
和C++一样,多条短语句用分号隔开放在同一行
高二的更新
JavaScript
稍微了解了一下JavaScript。还是比较习惯于沿用C++的写法。比如说使用==
和!=
,尽管我知道这么做很不安全,但是===
看着太丑了。又比如使用++
和--
运算符,虽然我到现在还不懂为什么用JS的人弃之如敝履。
定义函数使用和bash一样的function F(){}
而不是F=function(){}
。如果声明的数组是整型,用new Int32Array
而不是new Array
。字符串转整数使用+"123"
这样的写法。习惯于"A = "+A
而不是`A = ${A}`
。
应用的ES6特性主要是class
、=>
和let
。高精度偶尔用用。声明变量全部用let
。能用一行描述清楚的函数以及回调函数使用=>
声明。
一个代码片段,是我的2048游戏中的最核心的函数,可以看出和C++几乎是一模一样的:
Rust
Rust和Python类似,实现一个目标基本只有一种写法,玩不出什么花来。
像C++的using namespace std;
和Python的from X import *
一样,喜欢导入全部内容。并且多个有公共前缀的导入用大括号括在一起,比如:
由于Result
类型的返回值不使用就会有warning,然而我不想使用这个返回值,就直接用.ok()
了,反正丢弃Option
不会有事。
用fn
只声明全局函数;用||
只声明局部的函数。其实Rust的匿名函数也是可以递归的,参见我Min25筛模板的实现:
快读一般用extern"C"{fn getchar()->i32;}
,因为我实在是找不到什么原生的快速读入方式。快速输出用BufWriter::new(stdout())
。声明多个变量时习惯使用let (a,b)=(X,Y);
这样的写法。其他码风其实和C++差不太多。
补充:变量命名规则
有闲情逸致研究一番是因为知乎上刷到了这篇文章。
上篇忘说了,现在我写了个gedit的代码片段来创建新博客,真的很好用,大概是这样的:
为了进行统计,我特地修改了一下初中时写的分词程序。当时写的版本只能在Windows上用,现在我让它可以处理Linux中的英文数据(中文编码问题不会解决)。
首先筛选出所有我写过的OI程序:
然后运行分词程序,剔除一些无意义结果以及关键字、常数等等。我用过的几乎所有变量名都在下面列举出来了。可以看到三字母/单字母占到绝大多数。
循环变量
这是最常见的变量声明了。按顺序依次为i,j,k,l…,如果k
被占用了就改成i,j,t,u…
统计变量
t, _,$
双字母:sm
三字母:tot,cnt,top,ans
成对的变量
l/r(只用于区间),p/q(多用于数学),s/t(多用于源/汇),u/v(多用于边的起点/终点),x/y(泛指),n/m(多用于二维数组)
三字母:stt/end
数组名
一般数组(正常人都是这样):a,b,c…v(邻接表),w(权),e(边集数组),x,y(坐标)…
dp数组和多项式:f,g,h,…
特殊意义的数组(两字母,极少):fa(双亲),vl(权值)
特殊意义的数组(三字母):vis,dis,que,sta,ind(入度),dep,dfn,pos,siz,len,inv,fac(阶乘),cur(当前弧),ban…
函数名
三字母:ins,qry(泛指数据结构修改/查询,后可加1/2/3区分),sol,bfs,dfs(后加1/2/3),chk,rmq,tri(三分法)…
四字母:getf,Init,calc
结构体
二字母:st(泛指各种结构体,除非和st表重名),ev(事件),po(点)
数据结构/算法名:edge(边),segTree(线段树),Splay,LCT,Dinic,MCMF…