gpt4 book ai didi

recursion - LISP- 将递归改进为旋转列表函数中的尾递归

转载 作者:太空宇宙 更新时间:2023-11-03 18:48:46 24 4
gpt4 key购买 nike

我在 LISP 中有一个递归函数来向右或向左旋转列表,如下所示:

(如果数字是正数-向左推,如果是负数-向右推)

> (rotate-n ‘(5 6 7 8 9) -3)
(7 8 9 5 6)

> (rotate-n ‘(5 6 7 8 9) 3)
(8 9 5 6 7)

函数:

(defun rotate-n (L n)
(cond ((= n 0) L)
((> n 0) (rotate-n (rotate-left L) (- n 1)))
((< n 0) (rotate-n (rotate-right L) (+ n 1)))))

有没有办法使用尾递归得到相同的结果?rotate-right 和 rotate-left 函数工作正常。

编辑:我糊涂了。我上面写的函数是尾递归。如果我没记错的话,这个函数是出于相同目的的常规递归:

(defun rotate-n-r (L n)
(cond ((= n 0) L)
((> n 0) (rotate-left (rotate-n-r L (- n 1))))
((< n 0) (rotate-right (rotate-n-r L (+ n 1))))))

最佳答案

这是一个尾递归函数,它可以做你想做的事:

(defun rotate-list (list n)
(cond ((plusp n)
(rotate-list
(append (rest list) (list (first list)))
(1- n)))
((minusp n)
(rotate-list
(append (last list) (butlast list))
(1+ n)))
(t list)))

请注意,它占用(即分配内存)很多:

(ext:time (rotate-list '(5 6 7 8 9) 30))
Permanent Temporary
Class instances bytes instances bytes
----- --------- --------- --------- ---------
CONS 5 80 145 2320
----- --------- --------- --------- ---------
Total 5 80 145 2320
Real time: 3.2E-5 sec.
Run time: 0.0 sec.
Space: 2400 Bytes
(5 6 7 8 9)

一个非consing版本:

(defun nrotate-list (list n )
(cond ((plusp n)
(nrotate-list
(nconc (rest list) (progn (setf (cdr list) nil) list))
(1- n)))
((minusp n)
(nrotate-list
(nconc (last list) (nbutlast list))
(1+ n)))
(t list)))

不分配任何东西,同时仍然是尾递归:

(time (nrotate-list '(5 6 7 8 9) 30))
Real time: 2.3E-5 sec.
Run time: 0.0 sec.
Space: 0 Bytes
(5 6 7 8 9)

请注意,这两个版本在性能方面都非常愚蠢(他们为每次迭代扫描列表两次,即,它们的时间复杂度是 O(n*length(list))

高效的版本只会扫描列表一次(即时间复杂度O(length(list)))并且不会递归。

关于recursion - LISP- 将递归改进为旋转列表函数中的尾递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11004075/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com