@@ -1126,19 +1126,16 @@ \subsubsection{尾递归}
11261126\index {Tail call}
11271127\index {Tail recursion}
11281128\index {Tail recursive call}
1129- Note that both sum and product algorithms actually compute the result from right to left. We can change them
1130- to the normal way, that calculate the {\em accumulated} result from left to right. For example with sum,
1131- the result is actually accumulated from 0, and adds element one by one to this accumulated result till
1132- all the list is consumed. Such approach can be described as the following.
11331129
1134- When accumulate result of a list by summing:
1130+ 注意到无论是求和还是求积的算法都从右向左计算。我们可以修改它们的实现,从左向右\underline {累积计算}结果。求和时,结果从0开始累积,逐一将每个元素加到结果上,直到处理完全部列表。具体描述如下:
1131+
1132+ 当通过求和累积结果时:
11351133\begin {itemize }
1136- \item If the list is empty, we are done and return the accumulated result;
1137- \item Otherwise, we take the first element from the list, accumulate it to the result by summing, and go on
1138- processing the rest of the list.
1134+ \item 若列表为空,则累积结束,返回累积结果;
1135+ \item 否则,取出列表中的第一个元素,将其加到累积结果上,然后继续处理剩余的列表。
11391136\end {itemize }
11401137
1141- Formalize this idea to equation yields another version of sum algorithm.
1138+ 将这一描述形式化为定义,就可以得到另一种累加的算法。
11421139
11431140\be
11441141sum'(A, L) = \left \{
@@ -1150,25 +1147,16 @@ \subsubsection{尾递归}
11501147\right .
11511148\ee
11521149
1153- And sum can be implemented by calling this function by passing start value 0 and the list as arguments.
1150+ 最终求和可以通过调用这一函数实现。我们传入0作为累加的起始值,同时传入待累加的列表。
11541151\be
11551152sum(L) = sum'(0, L)
11561153\ee
11571154
1158- The interesting point of this approach is that, besides it calculates the result in a normal order from
1159- left to right; by observing the equation of $ sum'(A, L)$ , we found it needn't remember any intermediate
1160- results or states when perform recursion. All such states are either passed as arguments ($ A$ for example)
1161- or can be dropped (previous elements of the list for example). So in a practical implementation,
1162- such kind of recursive function can be optimized by eliminating the recursion at all.
1155+ 这一改进除了将计算的顺序恢复为从左向右之外,还有一个重要的特点。观察函数$ sum'(A, L)$ 的定义,我们发现它无需记录任何中间结果或者状态用于递归。所有的状态或者作为参数(例如$ A$ )传入接下来的递归调用,或者可以丢弃(例如列表中前面处理过的元素)。因此在实际的实现中,这样的递归函数可以进一步优化为循环,从而完全消除递归。
11631156
1164- We call such kind of function as `tail recursion' (or `tail call'), and the optimization of removing recursion in this case as
1165- 'tail recursion optimization' \cite {wiki -tail -call } because the recursion happens as the final action
1166- in such function. The advantage of tail recursion optimization is that the performance can be greatly
1167- improved, so that we can avoid the issue of stack overflow in deep recursion algorithms such as sum and
1168- product.
1157+ 我们称这样的函数为“尾递归”(或“尾调用”),对其消除递归的优化称为“尾递归优化”\cite {wiki -tail -call }。顾名思义,这类函数中,递归发生在最后一步。尾递归优化可以极大地提高性能,并避免由于过深递归造成的调用栈溢出。
11691158
1170- Changing the sum and product Haskell programs to tail-recursion manner gives the following modified
1171- programs.
1159+ 下面的Haskell例子程序给出了尾递归形式的求和与求积实现。
11721160
11731161\lstset {language=Haskell}
11741162\ begin{lstlisting}
@@ -1181,8 +1169,7 @@ \subsubsection{尾递归}
11811169 product' acc (x:xs) = product' (acc * x) xs
11821170\end {lstlisting }
11831171
1184- In previous section about insertion sort, we mentioned that the functional version sorts the elements
1185- form right, this can also be modified to tail recursive realization.
1172+ 在前面关于插入排序的部分,我们提到了函数式的实现从右向左对元素排序,我们也可以将其改为尾递归的形式。
11861173
11871174\be
11881175sort'(A, L) = \left \{
@@ -1194,15 +1181,14 @@ \subsubsection{尾递归}
11941181\right .
11951182\ee
11961183
1197- The the sorting algorithm is just calling this function by passing empty list as the accumulator argument.
1184+ 排序时,我们可以调用这一函数,传入一个空列表作为累积结果的起始值。
11981185\be
11991186sort(L) = sort'(\phi , L)
12001187\ee
12011188
1202- Implementing this tail recursive algorithm to real program is left as exercise to the reader.
1189+ 我们将它的具体实现作为练习留给读者。
12031190
1204- As the end of this sub-section, let's consider an interesting problem, that how to design an algorithm
1205- to compute $ b^n$ effectively? (refer to problem 1.16 in \cite {SICP }.)
1191+ 作为本节的结尾,我们考虑一个有趣的题目,如何设计一个算法来高效地计算$ b^n$ ?(参考\cite {SICP }中的1.16节。)
12061192
12071193A naive brute-force solution is to repeatedly multiply $ b$ for $ n$ times from 1, which leads to a
12081194linear $ O(n)$ algorithm.
0 commit comments