【问题标题】:for loops to recursionfor循环递归
【发布时间】:2012-08-10 05:44:46
【问题描述】:

我正在学习 uni 的数据结构课程,我正在努力理解它。我对 C 中的递归和循环有一个大致的了解,但我无法理解如何在 erlang 中实现循环。例如,我在 c 中的一个程序中有以下循环:

int ii;
double cos_lat[8];    
for(ii = 2, cos_lat[1] = cos(lat); ii <= 7;; ii++)
{
 cos_lat[ii] = cos_lat[1] * cos_lat[ii-1]
}

而且我不知道如何在 erlang 中实现它。 我知道我必须创建自己的循环定义,例如:

for(Max, Max, F) -> [F(Max)];
for(I, Max, F) -> [F(I)|for(I+1, Max, F)].

(取自实用的erlang)

然后调用如下:

for(2,7,fun(ii) -> // this is where i get stuck.

我认为我必须在数组(例如列表)上使用不同的数据结构,但我不确定如何访问列表。

感谢您的回复。只是一个更新(14/8)。我尝试对代码进行如下递归:

-module(cos1).
-export([cos_lat/1]).
cos_lat(Base, Iterator, Prev) -> [Base*Prev|cos_lat(Base,Iterator+1,Base*Prev)];
cos_lat(Base, 7, Prev) -> [].

并按如下方式调用它:

cos1:cost_lat(cos(lat),2,cos(lat).

但它就是不想工作! Erlang 真是一门令人困惑的语言。

【问题讨论】:

  • 请注意,这可能不是理解算法的最佳方式。您最好尝试理解算法的含义并以功能方式重新实现它,而不是机械地尝试移植命令式代码。

标签: arrays list loops erlang


【解决方案1】:

让我们看看“for”循环结构。

它包含初始化块、条件块和更新块。 循环有一个 state(它在开始时实际上是在初始化块中定义的)。 无论您要处理哪种数据结构,因为循环的结构通常是相同的。 循环状态封装了实际的数据结构。

此外,您可能会看到条件块和更新块通常是循环状态的函数。

使用这些信息,让我们创建通用循环函数:

-module( loops ).
-export( [ for/3 ] ).

for( State, ConditionFunc, LoopFunc ) ->
        case ConditionFunc( State ) of
                true ->
                        NewState = LoopFunc( State ),
                        % next iteration
                        for( NewState, ConditionFunc, LoopFunc );
                false ->
                        % terminate and return
                        State
        end.

例如,让我们创建一个从 1 到 10 的数字列表(在 eralng shell 中),使用我们的函数:

1> c(loops). 
{ok,loops}
2> 
2> ConditionFunc = 
2> fun( { 0, List } ) -> false;
2> ( _ ) -> true 
2> end.
#Fun<erl_eval.6.82930912>
3> 
3> LoopFunc = 
3> fun( { N, List } ) -> { N - 1, [ N | List ] } end. 
#Fun<erl_eval.6.82930912>
4> 
4> { _, Result } = loops:for( { 10, [] }, ConditionFunc, LoopFunc ).
{0,[1,2,3,4,5,6,7,8,9,10]}
5> 
5> Result.
[1,2,3,4,5,6,7,8,9,10]
6> 

这不是创建数字序列的最佳方法,它仅用于说明。总是你可能会发现更优雅的递归解决方案与循环解决方案。对于我们的示例,下一个解决方案更可取:

seq( A, B ) ->
        my_seq( A - 1, B, [] ).

my_seq( A, A, List ) ->
        List;
my_seq( A, B, List ) ->
        my_seq( A, B - 1, [ B | List ] ).

在外壳中:

1> loops:seq( 1, 10 ).
[1,2,3,4,5,6,7,8,9,10]

或者只使用标准库列表中的函数:)

2> lists:seq( 1, 10 ).
[1,2,3,4,5,6,7,8,9,10]

【讨论】:

  • 值得补充的是,由于 erlang 具有尾调用递归,因此您的 for 循环示例就像 C 的 for 循环一样在恒定空间中运行。例如,在 javascript 中这不是真的,因为堆栈大小与循环迭代次数一样大。
【解决方案2】:

此时:

for(2,7,fun(ii) -> // this is where i get stuck.

您的fun 正在使用索引调用,但您实际上对索引并不感兴趣 - 您需要在上一次迭代中添加到列表中的值。您可以将其作为第四个参数传递给您的 for 函数;第一次调用它时,您需要使用cos(lat) 播种它,并在每个递归步骤中使用新值。

【讨论】:

    【解决方案3】:

    以防万一有人感兴趣。我解决了如下问题:

        -module(cos_lat).
        -export([cos_lat/3]).
    
         cos_lat(_Base, _Iterator, _Prev) ->
         cos_lat(_Base, _Iterator, _Prev, []).
    
         cos_lat(_Base,0, _Prev, _Co) ->
         lists:reverse(_Co);
    
         cos_lat(Base, Iterator, Prev, Co) -> 
         cos_lat(Base, Iterator-1, Base*Prev, [Prev*Base|Co]).
    

    所以要调用它,你可以输入:

         cos_lat:cos_lat(math:cos(lat),7,math:cos(lat)).
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-18
      • 1970-01-01
      • 2015-12-28
      • 2017-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多