List 为什么在Scheme中反向O(n^2)的性能会下降?
假设我在Scheme中的反向函数按以下方式编码:List 为什么在Scheme中反向O(n^2)的性能会下降?,list,scheme,lisp,List,Scheme,Lisp,假设我在Scheme中的反向函数按以下方式编码: (define (reversee lst) (if (null? lst) '() (append (reversee (cdr lst)) (list (car lst))))) 为什么这个过程的性能O(n^ 2)?好,考虑函数需要做什么: 对于零元素列表,它只返回列表 对于1元素列表,它附加零元素列表和第一个元素的相反位置 对于2元素列表,它附加1元素列表和第一个元素的相反位置 。。。等等 很明显,为了反转
(define (reversee lst)
(if (null? lst)
'()
(append (reversee (cdr lst)) (list (car lst)))))
为什么这个过程的性能O(n^ 2)?
好,考虑函数需要做什么:- 对于零元素列表,它只返回列表
- 对于1元素列表,它附加零元素列表和第一个元素的相反位置
- 对于2元素列表,它附加1元素列表和第一个元素的相反位置
- 。。。等等
append
的复杂性。好吧,让我们写一篇我们能写的最好的append
:
(define (my-append l1 l2)
(if (null? l1)
l2
(cons (car l1) (my-append (cdr l1) l2))))
好的,那么这有多复杂?首先,只取决于l1
的长度,所以我们只需要担心:
- 如果
是零元素列表,则返回l1
l2
- 如果l2是一个单元素列表,则将其第一个元素添加到将其剩余元素附加到
l2
- 。。。等等
cons
和cdr
和car
需要恒定的时间。因此,append
的时间复杂度是第一个列表的长度
这意味着你的反向函数的时间复杂度是
n+n-1+n-2+…+一,
这是一个著名的结果,这样一个和的值是n(n+1)/2(你可以把这个结果写成((n+1)+(n-1+2)+(1+n))/2=((n+1)+(n+1))/2,和中有n个项,所以复杂度是n(n+1),它渐近地等于n^2
当然,有一个更好的版本是
reverse
。O(N)reverse
(定义(反向lst)
(让反向器(lst lst)
(倒“()))
(如果(空?lst)
颠倒的
(反向器(cdr lst)(cons(轿厢lst)反向‘‘‘‘‘)
(反面(1、2、3))
通过使用尾部递归方法构建反向列表,它只需遍历列表一次。追加与反向函数结合在一起本质上是一个嵌套循环。简短回答:因为您使用的是
append
,所以应该使用cons
来编写O(n)
解决方案。