个人各种代码习惯

C++ (最新):

一、空白字符

  1. 缩进使用长度为 4 的 Tab,一个长度为 4 的 Tab 记作一个单位的缩进。同一个代码块的缩进必须统一

  2. 大括号不换行,左大括号{与右圆括号)或函数名之间有空格。一般地,右大括号的缩进与上一级代码块 (含左大括号的行) 相同,中间的代码块向前缩进一个单位。例:

    struct fy {
    	int id, age;
    	void ak(int score) {
    		std::cout << "ckr ak zjoi2019 !" << std::endl;
    		return;
    	}
    };
    
  3. 特殊地,如果该函数 (过程/结构体) 比较短,则服从 "单行代码块" 格式:

    该格式中,左大括号前依然有空格,函数等在一行内完成,右大括号紧随其后。例:

    inline void up(int &x, const int y) {x < y ? x = y : 0;}
    struct pr {int x, y;} p[100];
    
  4. struct/class等声明完毕后,如果大括号后为分号,则紧随其后;如果为变量,则中间以一个空格分割。(例子见上两例)

  5. 左圆括号(前,如果是函数等非关键字 (不管是声明还是调用),中间不加空格,如果为 if/for/while 等关键字,中间以一个空格分割。例:

    sort(a, a + n);
    for (i = 0; i < n; ++i)
    	if (a[i] % 3)
    		fy_get(a[i]);
    
  6. do后如果有大括号,则它们之间以一个空格分割,其后的while前也有空格。(例子略)

  7. 单目运算符与操作数之间一律不添加空格。如:!x-y++i

  8. 一般的双目和三目运算符 (不包括中括号运算符),以及构造函数中的单冒号,运算符的两侧均要添加空格,如:a + 1p[x] == x ? x : (p[x] = ancestor(p[x])) 等。

  9. 当然,代表成员关系的双目运算符 (::, ., ->) 两侧不添加空格,如:std::sortb.firstit->second

  10. 特殊地,逗号运算符的左侧不能有空格,右边则必须有空格。

  11. 当一行有用分号隔开的多个语句时 (包括 for 循环的三个条件,甚至空的 for 循环),分号前不加空格,分号后必须加空格。例:

    x[id].v += v; x[id].sum += v * L;
    for (; ; ) {
    	for (j = 0; j < n; ++j)
    		if (test(j))
    			break;
    	++round;
    }
    
  12. 下列情况下必须以一个空行隔开:

    下列情况下推荐以一个空行隔开:

  13. 如果是行末注释,则注释与该行最后一个可见字符 (通常是大括号或分号) 之间用空格隔开。

二、常量

  1. 模数一律使用const,例:

    typedef long long ll;
    const ll mod = 998244353, root = 31;
  2. 表示数组大小的常量可以使用#define,也可以使用 const,但是如果有多个namespace 都需要定义数组时,则必须使用const,并采取如下方案:

    const int N = 100005;
    
    namespace fy {
    	const int N = ::N << 1, M = ::N * 5;
    	...
    }
    
    namespace sorting {
    	const int N = ::N * 3;
    	...
    }
    
  3. 表示数组大小的常量,往往要略大于数据规模,如 $10^5 + 5, 2 \times 10^7 + 5$ 等。

三、变量

  1. 全局变量必须代表着全局的意义,比如题目规模 n 或跟题目密切相关的主数组 a[i]

  2. 循环下标 ij一律定义成局部变量,并且如果频繁使用,则尽量在该过程开头写int i, j;等,如果使用次数较少,可以在 for 循环中即时定义。

  3. 类型定义一律使用 typedef允许使用 using极不推荐使用 #define

  4. 定义变量的行必须为新行,即不能在一个常规语句 (包括定义变量语句) 后又跟一个变量声明语句。即,下面的情形是禁止的:

    fy[2] += fy[1]; int i, j;
    for (i = 0; i < fy[2]; ++i) j += fy[1];
    
  5. 一行内不能定义太多 (10 个以上) 变量,否则会显得凌乱,更不能一行把所有 int 型变量定义完 (除非就四五个)。例:

    int V, E, Es;
    int first[N], next[M]; // adj
    int cnt = 0, id[N], low[N]; // tarjan
    int stc = 0, sta[N], in_stack[N]; // stack
    int scc = 0, bel[N], top[N]; // shrink
    int deg[N], size[N], que[N]; // toposort
    int f[N], g[N], hash[N]; // dp
    int ans, Count;
    
  6. 如果代码较长,且有比较多的子块时,推荐使用多个 namespace 来避免变量冲突,如 Tree::cnt, Graph::cnt, SA::cnt极不推荐使用诸如 cnt1, cnt2, first1, first2, cnt, Cnt 等命名方法。

四、函数

  1. 运行时间在 $O(1)$ 的单行函数尽量加 inline

  2. 外部比较器一律使用 (const T x, const T y) 型传值。

五、运算符

  1. 合理选用乘法和左移,除法和右移,模和按位与。下面是不明文规定的规则:当不开 -O2 时用位运算,开 -O2 时用乘除法,特殊地,(不管有没有 -O2) 模尽量改成按位与。

  2. 如果乘除模的参数非 $2$ 的幂次,一律使用乘、除、模,不使用自己手工移位,编译器的优化一定比你手工的强。特殊地,IO 优化中关于十进制的运算一律使用 * 10/ 10

  3. 在明确运算符的优先级情况下,可以不加括号,否则推荐加括号 (比如 &, |, ^ 三个运算符)。

    特别地,赋值运算符 = 和三目运算符 ? : 的优先级不确定 (都可能比对方高),此时一律加括号。(可以参考上面的并查集例子)

  4. 当前置和后置的自增运算符都能使用时,推荐使用前置的。尤其是 STL 的 iterator,更要如此。(如果开了 -O2,可能关系不大)

  5. sizeof 运算符后如果后面为变量或数组,则不加括号。

  6. long long 尽量使用 (ll)x * y 而不是 1ll * x * y,特殊地,如果还要乘一个系数 $2$ 等,可以使用 2ll * x * y。(转 double 类似)

六、杂项

  1. 尽量不使用 using namespace std;,这点极其重要,可以避免莫名其妙的变量冲突导致 Compile Error,需要使用的 STL 标准库中的内容在前面加 std::。频繁使用的函数 (如排序),可以在前面加 using std::sort;

  2. ifelse 不能位于同一行,else 之前必须换行。但是如果前面或后面是花括号,则在同一行。例:

    if (i % p[j]) ++a;
    else ++b;
    
    if (a + b == 100) {
    	std::cout << "ok\n";
    } else {
    	std::cout << "failed\n";
    }
    
  3. 如果一个 if - else 语句里面的操作比较短可以被三目运算符优化掉,尽量去手动优化,因为 if 的误判惩罚很高。比如,上例的两个语句可以改成:

    i % p[j] ? ++a : ++b;
    std::cout << (a + b == 100 ? "ok\n" : "failed\n");
    
  4. 循环上限尽量不使用函数型,比如 vec.size(),尽量替换成下列两种方案之一:

    for (i = (int)vec.size() - 1; i >= 0; --i)
    	// do something;
    
    for (n = (int)vec.size(), i = 0; i < n; ++i)
    	// do something;
    
  5. 所有预编译指令 # 均位于程序开头 (有特例);类型声明、常量定义紧随其后;接着是全局变量定义;所有全局变量定义完毕后才是定义所有的函数。

    这其中每两个部分之间均用空行分隔。

Latex:

一、运算符

  1. 小于等于,大于等于一律使用 \leq, \geq

  2. 空集一律使用 \varnothing,不使用 \emptyset

  3. 所有运算符 (不论单目还是双目) 与操作数之间必须以空格隔开,例:$1 \leq i < j \leq n$

  4. 行内公式中,分数和二项式系数尽量使用 \dfrac\dbinom。行内的和式、乘积式均要添加 \limits

  5. 如果行内公式不提供可视版本 (如 Stirling 数),则需在前面手动添加 \displaystyle

  6. 按位与、或、异或、非分别使用 \mathbin{\&}, \mid, \oplus, \neg,效果:$a \mathbin{\&} b, a \mid b, a \oplus b, \neg a$。

  7. 逻辑与、或、异或、非分别使用 \wedge, \vee, \oplus (或 \veebar), \neg (或 !),效果 $a \wedge b, a \vee b, a \oplus b (a \veebar b), \neg a (! a)$。

二、正斜体

  1. 标准数学函数必须使用正体,如 \log, \sin, \gcd 等。

  2. 如果库里面没有,则需使用 \mathrm\operatorname 使之变为正体。

  3. 微分算子 $\mathrm dx$ 的 d 和虚数单位 $\mathrm i$ 使用正体。

  4. 若字母表示变量,则使用斜体,若字母表示物理单位等,则使用正体。例:$m = 30 \mathrm{kg} + m_0$,效果:$m = 30 \mathrm {kg} + m_0$。

三、杂项

  1. 当有多个不等式,每个不等式有多个变量时 (尤其是限制与约定部分),变量之间用逗号隔开,不等式之间用分号隔开。例:

    $1 \leq n, m \leq 10^5; a_i, b_i \leq 10^9; a_i \neq b_i$,效果:$1 \leq n, m \leq 10^5; a_i, b_i \leq 10^9; a_i \neq b_i$。

Markdown/HTML:

一、空白字符

  1. 中文和英文、公式之间必须以一个空格隔开,但是和中文的标点之间不能有空格。例:

    fy 最可爱啦,她要 AK!
    给定 $n$ 个数 $a_1, a_2, \cdots, a_n$。
    
  2. 超链接的两侧可以加空格,但是如果不加空格,则必须按照中西文遵守第 1 条规则。

  3. <code> 标签两侧可以不加空格,但是推荐加空格。

  4. 数字与单位之间尽量不加空格。

二、标签

  1. 自闭合 (self-closing) 标签必须在后面添加 " />" 三个字符,例:<br />, <img src="fy.jpg" alt="fy" />

  2. <img> 标签必须添加 alt 属性。

  3. 超链接 <a> 标签尽量添加 target="_blank" 选项。

  4. 加粗、斜体、下划线、删除线尽量使用 <strong>, <em>, <ins>, <del> 标签。

  5. 其它字体属性 (如颜色) 尽量使用 CSS,如 <font color="red"> 尽量改为 <span style="color: red">

    类似地,图片的宽度尽量从 <img width="800px"> 改为 <img style="width: 800px">

  6. 较为生僻的缩写必须在每一处使用 <abbr> 标签展示全名,例:<abbr title="Euler Tour Tree, 欧拉环游树">ETT</abbr>,效果:ETT