Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何实现尾递归列表追加?

如何实现尾递归列表追加?
EN

Stack Overflow用户
提问于 2010-05-19 16:33:27
回答 3查看 7.8K关注 0票数 9

一个简单的附加函数,如下所示(在F#中):

代码语言:javascript
运行
AI代码解释
复制
let rec app s t =
   match s with
      | [] -> t
      | (x::ss) -> x :: (app ss t)

当s变大时会崩溃,因为函数不是尾递归的。我注意到F#的标准append函数不会在大列表中崩溃,所以它必须以不同的方式实现。所以我想知道: append的尾递归定义是什么样子的?我想出了这样的东西:

代码语言:javascript
运行
AI代码解释
复制
let rec comb s t =
   match s with
      | [] -> t
      | (x::ss) -> comb ss (x::t)
let app2 s t = comb (List.rev s) t 

这是可行的,但看起来相当奇怪。有没有更优雅的定义?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-05-19 16:52:26

传统(非尾递归)

代码语言:javascript
运行
AI代码解释
复制
let rec append a b =
    match a, b with
    | [], ys -> ys
    | x::xs, ys -> x::append xs ys

具有累加器(尾递归)的

代码语言:javascript
运行
AI代码解释
复制
let append2 a b =
    let rec loop acc = function
        | [] -> acc
        | x::xs -> loop (x::acc) xs
    loop b (List.rev a)

带有延续(尾递归)

代码语言:javascript
运行
AI代码解释
复制
let append3 a b =
    let rec append = function
        | cont, [], ys -> cont ys
        | cont, x::xs, ys -> append ((fun acc -> cont (x::acc)), xs, ys)
    append(id, a, b)

将任何非尾递归函数转换为带有延续的递归函数是非常直接的,但我个人更喜欢累加器,因为它具有直接的可读性。

票数 26
EN

Stack Overflow用户

发布于 2010-05-19 17:44:53

除了朱丽叶发布的内容:

使用序列表达式的

在内部,序列表达式生成尾递归代码,因此这很好地工作。

代码语言:javascript
运行
AI代码解释
复制
let append xs ys = 
  [ yield! xs
    yield! ys ]

使用可变.NET类型

David提到,F#列表可能会发生变化--但这仅限于F#核心库(并且该功能不能被用户使用,因为它破坏了函数概念)。您可以使用可变的.NET数据类型来实现基于突变的版本:

代码语言:javascript
运行
AI代码解释
复制
let append (xs:'a[]) (ys:'a[]) = 
  let ra = new ResizeArray<_>(xs)
  for y in ys do ra.Add(y)
  ra |> List.ofSeq

这在某些情况下可能很有用,但我通常会避免F#代码中的突变。

票数 15
EN

Stack Overflow用户

发布于 2010-05-19 16:56:25

快速浏览一下F#源代码,它的尾部似乎是内部可变的。一个简单的解决方案是在将第一个列表的元素合并到第二个列表之前反转第一个列表。这与反转列表一起,对于以递归方式实现tail来说是微不足道的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2867514

复制
相关文章
【说站】python尾递归优化如何实现
2、通过这种方式,编译器或解释器可以对尾递归进行优化,从而使递归本身仅占用一个栈帧,而不会发生栈溢出。
很酷的站长
2022/11/23
4900
【说站】python尾递归优化如何实现
递归与伪递归区别,Python 实现递归与尾递归
      递归函数在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函 数。(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。 递归一般用于解决三类问题:  (1)数据的定义是按递归定义的。(n的阶乘)    (2)问题解法按递归实现。(回溯)    (3)数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索) 递归的缺点:   递归解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,
学到老
2018/03/16
2K0
递归与尾递归
  本博客前面介绍了不少跟递归的思想相关的例子,比如“汉诺塔”,“八皇后”等。因最近又回忆起“尾递归”,故本文通过2个例子再跟大伙儿探讨一下尾递归。。。
云海谷天
2022/08/09
7650
递归与伪递归区别,Python 实现递归与尾递归
      递归函数在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函 数。(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
学到老
2019/02/14
1.5K0
递归与尾递归
在介绍递归与尾递归之前,我们来看看递归的定义:程序调用自身的编程技巧称为递归( recursion)
踏浪
2019/11/28
1K0
尾调用和尾递归
尾调用是函数式编程中一个很重要的概念,当一个函数执行时的最后一个步骤是返回另一个函数的调用,这就叫做尾调用。
leocoder
2018/10/31
1.1K0
30秒了解尾递归和尾递归优化
尾递归和尾递归优化 之前提到过尾调用,尾调用就是函数的最后一步调用另外一个函数。那么递归就是调用自身,尾递归就是再函数的最后一步调用自身。? 在计算机学里,尾调用是指一个函数里的最后一个动作是返回一个
JS菌
2019/04/10
9560
30秒了解尾递归和尾递归优化
尾递归函数
Kotlin 支持一种称为尾递归的函数式编程风格。 这允许一些通常用循环写的算法改用递归函数来写,而无堆栈溢出的风险。 当一个函数用 tailrec 修饰符标记并满足所需的形式时,编译器会优化该递归,留下一个快速而高效的基于循环的版本:
阿超
2022/10/31
7390
大家都知道递归,尾递归呢?什么又是尾递归优化?
今天,我们来聊聊递归函数。为啥突然想到递归?其实就从电影名字《恐怖游轮》《盗梦空间》想到了。
程序猿石头
2020/07/14
1.6K0
大家都知道递归,尾递归呢?什么又是尾递归优化?
递归与尾递归简析
与之相对的是非尾递归函数,你先执行递归调用,然后获取递归调用的结果进行计算, 这样你需要先获取每次递归调用的结果,才能获取最后的计算结果。看下面计算n阶乘的函数,它是一个非尾递归函数。我们发现cal(n-1)返回的值被cal(n)使用,因此对cal(n-1)的调用并不是cal(n)所做的最后一步。
java达人
2020/12/16
8420
递归与尾递归总结
关于递归的概念,我们都不陌生。简单的来说递归就是一个函数直接或间接地调用自身,是为直接或间接递归。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。用递归需要注意以下两点:(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
狼啸风云
2019/11/05
7980
javascript尾递归优化
JS中的递归我们来看一个阶乘的代码function foo( n ){ if(n <= 1){ return 1; } return n * foo( n - 1 );}foo(5); // 120下面分析一下,代码运行过程中,执行上下文栈是怎么变化的这个代码是在全局作用域中执行的,所以在foo函数得到执行之前,上下文栈中就已经被放入了一个全局上下文。之后执行一个函数,生成一个新的执行上下文时,JS引擎都会将新的上下文push到该栈中。如果函数执行完成,JS引擎会将对应的上下文从上下文栈中弹出
hellocoder2029
2022/10/21
6460
递归尾调用优化
尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是return调用另一个函数。
wade
2020/04/24
7030
Python中的尾递归
尾递归的原理:当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。编译器可以做到这点,因为递归调用是当前活跃期内最后一条待执行的语句,于是当这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率会变得更高。
K同学啊
2019/01/22
1.3K0
Kotlin中尾递归函数
上面函数将调用自身作为其执行体的最后一行代码,且递归调用后没有更多代码,因此可 以将该函数改为尾递归语法。此时,上面函数可改为如下形式
对话、
2022/02/22
8340
尾递归的后续探究
本文探讨了尾递归调用优化在JavaScript引擎中的实现细节,并分析了尾递归调用出现调用栈溢出的原因。文章提出了两种解决方案:1.显式地定义尾递归调用;2.采用尾调用优化语法。尾调用优化语法可以解决隐式优化和调用栈丢失的问题。
IMWeb前端团队
2017/12/29
1K0
尾递归的后续探究
尾递归的后续探究
去年大致也是这个事件,曾经探索过尾调用(PTC)相关的内容,并总结了一片文章——朋友你听说过尾递归吗。同时在文章的最后也留下了一个坑:
IMWeb前端团队
2019/12/03
1.5K0
尾递归的后续探究
面试官:说一说递归如何优化-尾递归优化
编者荐语:本文旨在帮助大家掌握递归的性能优化方案——尾递归优化,以及如何对下列函数用尾递归进行优化?
coder_koala
2020/09/08
4.2K0
面试官:说一说递归如何优化-尾递归优化
尾递归是怎么一回事?什么是尾递归?
50%的算法问题都能通过递归来解决,倒不是说递归本身有多厉害,只是说明递归的思想让很多复杂的问题变得简单! 啥? 了解数据结构的人都知道, 树结构本身就是用递归定义的,所以解决树相关的问题会优先考虑递
zhaoolee
2018/04/19
2.2K0
尾递归是怎么一回事?什么是尾递归?
点击加载更多

相似问题

实现尾递归列表操作

31

尾递归实现

116

实现尾递归

11

尾递归函数在列表中追加元素

38

如何在Scheme/Racket中使用尾递归实现追加过程?

24
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文