簡體   English   中英

方案:以原始順序重建列表的迭代過程?

[英]Scheme: Iterative process to reconstruct a list in original order?

我的問題是:如何編寫一個使用尾調用的過程,並以不相反的順序構造一個列表。 為了說明我的意思,這里是一個非常簡單的迭代過程示例,它創建了一個列表的副本:

(define (copy-list ls)
    (define (iter cp-ls rest-ls)
      (if (null? rest-ls)
          cp-ls
          (iter (cons (car rest-ls) cp-ls) (cdr rest-ls))))
    (iter '() ls))

問題是,由於其中的元素是迭代順序cons ED一起,返回的列表末端向上翻轉。 是的,你可以很容易地通過做解決這個(reverse cp-list) ,而不是僅僅cp-listif -塊,但這個問題是reverse是一個遞歸的過程。 利用此過程將抵消尾調用優勢,即堆棧大小隨輸入大小線性增長。

那么,基本上,如何編寫一個像上面提到的那樣以正確的順序返回列表而不使用任何遞歸過程的過程?

謝謝

請注意,您的iter過程幾乎完全reverse實現的方式 - 不,這不是您在問題中提到的遞歸過程。

在 Racket 中檢查程序的定義很簡單:在沒有定義的編輯窗口中鍵入reverse ,右鍵單擊它,然后選擇“跳轉到定義”。 它會有一些用於優化和錯誤處理的額外代碼,但算法的核心在letrec-values部分,它與您的iter過程相同。 所以,如果我們已經有了:

(define (reverse ls)
  (let iter ((cp-ls '()) (rest-ls ls))
    (if (null? rest-ls)
        cp-ls
        (iter (cons (car rest-ls) cp-ls) (cdr rest-ls)))))

然后, copy-list只是:

(define (copy-list ls)
  (reverse (reverse ls)))

順便說一句,這並不是很有用 - 如果您沒有改變列表,那么復制它就沒有意義。 一個反向的反向只是原始的東西,不是嗎? 事實上,任何在不可變copy-list上操作的copy-list實現,出於所有意圖和目的,都等同於身份過程:

(define (copy-list ls) ls)

您可以使用繼續傳遞樣式, return ,下面 -

(define (copy-list ls)
  (let loop ((ls ls) (return identity))
    (if (null? ls)
        (return null)
        (loop (cdr ls)
              (lambda (r) (return (cons (car ls) r)))))))

(copy-list '(1 2 3 4))
; '(1 2 3 4)

這是這個過程的樣子——

(copy-list '(1 2 3 4))
(loop '(1 2 3 4) identity)
(loop '(2 3 4) (lambda (r) (identity (cons 1 r))))
(loop '(3 4) (lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))))
(loop '(4) (lambda (r) ((lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))) (cons 3 r))))
(loop '() (lambda (r) ((lambda (r) ((lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))) (cons 3 r))) (cons 4 r))))
((lambda (r) ((lambda (r) ((lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))) (cons 3 r))) (cons 4 r))) null)
((lambda (r) ((lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))) (cons 3 r))) '(4))
((lambda (r) ((lambda (r) (identity (cons 1 r))) (cons 2 r))) '(3 4))
((lambda (r) (identity (cons 1 r))) '(2 3 4))
(identity '(1 2 3 4))
'(1 2 3 4)
(map (lambda(x) x) l)

將復制列表l並且它不是遞歸編寫的。

(let ((l '(1 2 3 4)))
  ((fold-right (lambda (e acc)
                 (lambda (x) (cons x (acc e))))
               (lambda (x) (list x))
               (cdr l))
   (car l)))

是另一種無需遞歸復制列表但使用幺半群的形式。

其他:

(let ((l '(1 2 3 4)))
  (car ((fold-right (lambda (e acc)
                      (lambda (x) (acc (append x (list e)))))
                    (lambda (x) (list x))
                    (cdr l))
        (list (car l)))))

其他:

(let ((l '(1 2 3 4)))
  (cdr ((fold-left (lambda (acc e)
                     (lambda (x) (cons x (acc e))))
                   (lambda (x) (list x))
                   l)
        'first)))

其他(由Will建議):

(let ((l '(1 2 3 4)))
  ((fold-right (lambda (e acc)
                 (lambda (k) (k (acc (lambda (es) (cons e es))))))
               (lambda (z) (z (list))) l)
   (lambda (es) es)))

還有很多其他方法可以復制列表。 通常,要進行復制,您需要直接或間接調用cons

正如評論中提到的,並非所有這些方法都使用迭代過程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM