algorithm - 如何在树形数据结构上实现尾递归

标签 algorithm recursion scheme racket tail-recursion

我正在使用 Racket,但这个问题适用于任何支持尾递归的方案。

我很熟悉在平面列表上实现尾递归的传统模式,大致是这样的:

(define (func x [acc null])
  (if (null? x)
      acc
      (func (cdr x) (cons (do-something-to (car x)) acc))))

在这种情况下,func 处于尾部位置。

但是当我使用树时,即具有递归嵌套列表的列表,我最终会像这样使用 map 进行递归下降:

(define (func2 x)
  (cond
    [(atom? x) (do-something-to x)]
    [(list? x) (map func2 x)]))

这有效,但是 func2 不再处于尾部位置。

您能否——如果可以,您会如何——以尾递归方式重写 func2

(撇开它是否提高性能的问题,这不是我要问的问题。)

最佳答案

正如其他答案中已经正确陈述和解释的那样,对此使用尾递归没有任何优势。但是,由于您对它的完成方式感兴趣,这里是我实现过一次的 deep-map 函数。如果您对镜像列表感到满意,代码会更清晰。

(define deep-map
  (λ (f lst)
    (let tail-rec ([stack `(,lst)] [acc '(())])
      ;(displayln (~a "Stack: " stack " / Acc: " acc))
      (cond [(null? (car stack))
             (if (null? (cdr stack))
                 (car acc)
                 (tail-rec (cdr stack)
                           `(,(append (cadr acc) `(,(car acc))) . ,(cddr acc))))]
            ;; The first element is a list and is being put on the stack
            [(list? (caar stack))
             (tail-rec `(,(caar stack) . (,(cdr (car stack)) . ,(cdr stack)))
                       `(() . ,acc))]
            ;; Process next element
            [else (tail-rec `(,(cdar stack) . ,(cdr stack)) 
                            `(,(append (car acc) `(,(f (caar stack)))) . ,(cdr acc)))]
            ))))

一个简单的例子:

> (deep-map add1 '(1 ((2) 3)))
Stack: ((1 ((2) 3))) / Acc: (())
Stack: ((((2) 3))) / Acc: ((2))
Stack: (((2) 3) ()) / Acc: (() (2))
Stack: ((2) (3) ()) / Acc: (() () (2))
Stack: (() (3) ()) / Acc: ((3) () (2))
Stack: ((3) ()) / Acc: (((3)) (2))
Stack: (() ()) / Acc: (((3) 4) (2))
Stack: (()) / Acc: ((2 ((3) 4)))
'(2 ((3) 4))

关于algorithm - 如何在树形数据结构上实现尾递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27428946/

相关文章:

java - 使用递归求和所有阶乘的值

recursion - 迭代是递归吗?

scheme - PLT方案: Converting one of the macros in 'Casting SPELs in LISP'

functional-programming - 自学SICP你会用什么语言?

scheme - 对于应用顺序,参数的评估顺序是什么?从左到右还是从右到左?

python 图像识别

c++ - 将 std::function 作为参数传递给 for_each

javascript - 这个递归函数如何改变 'history' 变量?

c++ - 为什么比较运算符这么快?

java - 旋转数组