ARTS Week 25

Algorithm

本周的 LeetCode 题目为 371. 两整数之和

给你两个整数 ab,不使用 运算符 +-,计算并返回两整数之和。

输入:a = 1, b = 2
输出:3

根据两个二进制位相加的四种情况如下:

0 + 0 = 0
0 + 1 = 1
1 + 0 = 1
1 + 1 = 0 (进位)

在不考虑进位的情况下,无进位加法结果为 a^b;而是否进位取决于 a&b,因此进位的结果为 (a&b)<<1。于是,我们可以将整数a和b的和,拆分为a和b的无进位加法结果与进位结果的和。因为每一次拆分都可以让需要进位的最低位至少左移一位,又因为a和b可以取到负数。因为因为有符号整数用补码来表示,所以0和负数也适用以上方法。

class Solution {
    public int getSum(int a, int b) {
        while (b != 0) {
            int carry = (a & b) << 1;
            a = a ^ b;
            b = carry;
        }
        return a;
    }
}

Review

本周 Review 的英文文章为:编写代码注释的最佳实践

多的代码注释不代表其质量有所保证,好的注释应可以帮助其他人更容易地去理解代码,下面是作者提出的一些如何保证代码质量的建议:

  1. 注释不应与代码重复。

不好的示例

i = i + 1;         // Add one to i

一个更极端的错误示例

// create a for loop // <-- comment
for // start for loop
(   // round bracket
    // newline
int // type for declaration
i    // name for declaration
=   // assignment operator for declaration
0   // start value for i
  1. 好的注释不能成为不清晰代码的借口。

不好的示例,变量n的意义不明确

private static Node getBestChildNode(Node node) {
    Node n; // best child node candidate
    for (Node node: node.getChildren()) {
        // update n if the current state is better
        if (n == null || utility(node) > utility(n)) {
            n = node;
        }
    }
    return n;
}

好的示例,应该将变量n改名为bestNode,这样不需要注释也足以让他人理解。

private static Node getBestChildNode(Node node) {
    Node bestNode;
    for (Node currentNode: node.getChildren()) {
        if (bestNode == null || utility(currentNode) > utility(bestNode)) {
            bestNode = currentNode;
        }
    }
    return bestNode;
}
  1. 如果不能写清楚的注释,可能是代码有问题。Unix 源代码中最臭名昭著的注释是“You are not expected to understand this(你不应该理解这个)”,不幸的是,写下这些注释的丹尼斯里奇,他自己也并不完全理解代码,后来不得不重写代码。

  2. 注释应该消除混乱,而不是引起混乱。如果你的代码注释会引起歧义,请将其删除。

  3. 在注释中解释单一的代码。

不好的示例,代码中不应该去解释大家都能理解的代码,除非是在给新手编写教程。

final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
    return null;
}
  1. 提供复制代码的原始来源的链接。下面是一个好的示例:
/** Converts a Drawable to Bitmap. via https://stackoverflow.com/a/46018816/2219998. */
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
  1. 在最有帮助的地方包含指向外部参考的链接。有时候,也可以给出手册的链接:
// http://tools.ietf.org/html/rfc4180 suggests that CSV lines
// should be terminated by CRLF, hence the \r\n.
csvStringBuilder.append("\r\n");
  1. 修复错误时添加注释。下面是一个好的示例:
// NOTE: At least in Firefox 2, if the user drags outside of the browser window,
// mouse-move (and even mouse-down) events will not be received until
// the user drags back inside the window. A workaround for this issue
// exists in the implementation for onMouseLeave().
@Override
public void onMouseMove(Widget sender, int x, int y) { .. }
  1. 使用注释来标记不完整的实现。下面是一个示例:
// TODO(hal): We are making the decimal separator be a period, 
// regardless of the locale of the phone. We need to think about 
// how to allow comma as decimal separator, which will require 
// updating number parsing and other places that transform numbers 
// to strings, such as FormatAsDecimal

事实上,很多代码注释其实都和下图中展示的一样:

Figure 1

Tip

clock() 函数和 gettimeofday() 函数的异同:

  • 共同点:二者都可以获取当前的时间,通过对前后的当前时间的求差值,进而得到某段代码的运行时间
  • 不同点:clock()是C语言库函数,也就意味着在任何系统下都可以使用;而 gettimeofday() 函数仅仅是Linux系统中的函数,因此其仅可以在Linux系统中使用。

Share

发布了C语言的读写CSV的教程三部曲,各个平台的阅读数据明显比 ARTS 系列多,可见平台和大家更喜欢有具体某一点的教程,未来要更多的创造此类型的文章。

posted @ 2022-02-13 20:52  永远是萌新的阿岩  阅读(47)  评论(0编辑  收藏  举报