球拍中追加名单的复杂性

时间:2017-08-02 07:06:28

标签: list scheme racket complexity-theory

(define (append l1 l2)
    (if (null? l1) l2 [cons (car l1) (append (cdr l1) l2)]))

这个功能应该是多么复杂。据我说它应该是O(长度l)因为应该在堆上创建一个新列表并创建并返回一个新列表。

因此,如果它是O(长度为l),则(append l1 l2)函数的复杂度必须为O(长度l1 +长度l2),因为

SELECT CCY_RATE.MID_REVAL_RATE
FROM   curr_currency_market_his CCY_RATE
WHERE  CCY_RATE.CURR_ID = a.CCY_BOUGHT
     AND CCY_RATE.CURRENCY_MARKET = 1
     AND CCY_RATE.LEAD_COMPANY = 1
     AND CCY_RATE.BANKING_DATE  = DATE_SUB(:Report_date, INTERVAL 1 DAY)

在基本情况下,在堆上创建一个新列表,因此需要时间O(l2),递归需要时间O(l1)所以总复杂度为O(l1 + l2)

但是我在课堂上被教导在课堂上追加是O(l1),这是正确的吗?

Screenshot to prove that an entire new list is created on heap 1(否则在更改l1或l2 l3时必须更改!!

2 个答案:

答案 0 :(得分:0)

(define (f l) l)只返回其参数,不会复制,因此其复杂度为O(1),而您提供的append定义复制第一个列表,因此其复杂度为O(长度l1)。

考虑您给出的示例:(set! l2 '(4 5))不修改任何列表,它修改全局变量l2,使其指向新列表。所以l3没有变化。您可以使用set-cdr!set-car!修改列表,如果您尝试此操作(假设使用可以修改列表的方言),您会看到l3也被修改。< / p>

答案 1 :(得分:0)

Renzo假设参数已经在列表中,并且一些解释器可能是正确的。大多数eval的实现都是这样的,然后实际的lambda实现在evlis之前执行apply

最有效的Scheme实现将代码作为堆栈机器执行,因此每个变量只是一个指向堆栈的偏移指针,就像在本机程序中一样。要使(lambda l l)工作l需要从所有参数中解决,以便在函数的开头执行O((length n))任务,并且它有一个堆栈参数,其地址为新创建的清单。然后它返回该地址,可能是将它留在堆栈上。

append将列表作为两个参数。因此,它不需要从堆栈创建它们,因为堆栈有两个地址。 append制作l1的副本,当l1为空列表时,它使用l2而不对其执行任何操作,作为最后一对的cdr`。举个例子:

(define test1 '(1 2 3))
(define test2 '(4 5 6))
(define test3 (append test1 test2))
test3 ; ==> (1 2 3 4 5 6)

(eq? (cdddr test3) test2) ; ==> #t (they are the same)

(define test4 (append test1 '()))
test4 ; ==> (1 2 3)

(equal? test1 test4) ; ==> #t
(eq? test1 test4)    ; ==> #f (they just look the same)

以下是第一个append所涉及的步骤:

(append '(1 2 3) '(4 5 6))                        ; ==
(cons '1 (append '(2 3) '(4 5 6))                 ; ==
(cons '1 (cons '2 (append '(3) '(4 5 6)))         ; ==
(cons '1 (cons '2 (cons 3 (append '() '(4 5 6)))) ; ==
(cons '1 (cons '2 (cons 3 '(4 5 6)))              ; ==

您可以看到它是O((+ 1 (length l1)))