之前一直有听说这么一句话:Programs = Algorithms + Data Structures。但要具体点描述就说不出什么了。

这种说法是1976年在 《Algorithms + Data Structures = Programs》 提出的,即 程序 = 算法 + 数据结构。表达式的重点更倾向于 数据结构,认为如果数据结构设计的好,算法也会变得简单,而且一个好的通用的算法应该可以用在不同的数据结构上。

后面,在1979年,英国的逻辑学家和计算机科学 Robert Kowalski 发表了论文 《Algorithms = Logic + Control》, 其中表述的观点为:

任何算法都会有两个部分, 一个是 Logic 部分,这是用来解决实际问题的。另一个是 Control 部分,这是用来决定用什么策略来解决问题。Logic 部分是真正意义上的解决问题的算法,而 Control 部分只是影响解决这个问题的效率。程序运行的效率问题和程序的逻辑其实是没有关系的。我们认为,如果将 Logic 和 Control 部分有效地分开,那么代码就会变得更容易改进和维护。

Algorithms = Logic + Control 想表达的是,数据结构不复杂,复杂的是算法,也就是程序中的业务逻辑。算法部分还可以继续细分,拆分成两部分逻辑,一个是 业务逻辑,一个是 控制逻辑。因此,程序中通常会有两种代码,一种是 真正的业务逻辑代码,另一种是 控制我们程序代码—-控制代码,两者分工明确。

算法的效率提升往往是 通过提升控制逻辑部分效率来改善。之前就有一个很好的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
template<class Iter, class T, class Op>
T reduce(Iter start, Iter end, T init, Op op) {
    T result = init;
    for (; start != end; start++) {
        result = op(result, *start);
    }
    return result;
}

struct Employee {
    string name;
    string id;
    int vacation;
    double salary;
};

template<class T, class Cond>
struct counter {
    Cond cond;
    size_t operator()(size_t c, T t) {
        return c + (cond(t) ? 1 : 0);
    }
};


template<class Iter, class Cond>
size_t count_if(Iter begin, Iter end, Cond c) {
    auto op = counter<typename Iter::value_type, Cond>{c};
    return reduce(begin, end, size_t(0), op);
}
  • 控制逻辑部分 - reduce函数,仅作遍历操作。
  • 业务逻辑部分 - 传入的 Op 函数,有外界传入,分离了 控制逻辑业务逻辑
  • 数据结构 - Employee结构体的迭代器对象,通过分离 控制逻辑业务逻辑,程序不再关系数据结构是什么样的,数据结构中也不需要实现自有的逻辑代码。

最终程序的运行效率转嫁到迭代器对象的遍历操作上,也就是 控制逻辑部分

结合上面的两个表达式:

  • Programs = Algorithms + Data Structures
  • Algorithms = Logic + Control

我们得到了:Program = Logic + Control + Data Structure

这应该是目前程序编写最规范的表示了。

在写代码的时候,很多时候我们习惯将 业务逻辑控制逻辑 放在一起,这样做的直接后果就是导致了 代码的耦合度急剧增加,大大的增强了程序的复杂度。

因此,

有效地分离 Logic、Control 和 Data 是写出好程序的关键! 有效地分离 Logic、Control 和 Data 是写出好程序的关键! 有效地分离 Logic、Control 和 Data 是写出好程序的关键!