2015-03-25 37 views

回答

2

如果尾部(最後一個元素)的cdr指向列表的開頭,則列表爲circular per definition。但是,您也可以有一個圓形列表,尾部的cdr指向列表中的任意元素。 A good algorithm檢測循環列表是烏龜和兔子算法。示例實現在this page處給出。

的代碼如下(信貸以上鏈接的頁面的作者):

編輯:我修改了代碼,因爲它包含一個錯誤由Sylwester指出。

(define (has-cycle-h slow-ls fast-ls) 
    (cond 
    ((null? fast-ls) #f) 
    ((null? (cdr fast-ls)) #f) 
    ((eq? slow-ls fast-ls) #t) 
    (else (has-cycle-h (cdr slow-ls) (cddr fast-ls))))) 

(define (has-cycle? ls) 
    (cond 
    ((null? ls) #f) 
    (else (has-cycle-h ls (cdr ls))))) 


;; Create cyclic list 
(define l (cons 1 (cons 2 (cons 3 (cons 4 '()))))) 
(set-cdr! (cdr (cdr (cdr l))) l) 
;; Results in: 
;+---+ +---+ +---+ +---+ 
;| 1 +--->| 2 +-->| 3 +--->| 4 | 
;+-+-+ +---+ +---+ +-+-+ 
;^      | 
; |       | 
; +-------------------------+ 

(has-cycle? l) ; Evaluates to #t 


;; Create list 
(define l (cons 1 (cons 2 (cons 3 (cons 4 '()))))) 
;; Make it circular by pointing the tail to the second element. 
(set-cdr! (cdr (cdr (cdr l))) (cdr l)) 
;; Results in: 
;+---+ +---+ +---+ +---+ 
;| 1 +--->| 2 +-->| 3 +--->| 4 | 
;+---+ +-+-+ +---+ +-+-+ 
;   ^    | 
;   |    | 
;   +----------------+ 
(has-cycle? l) ; Evaluatores to #t 

; Regular list 
(has-cycle? '(1 1 1 1 1 1 1)) ; Evaluates to #f 

沒有用於檢測循環列表的BIF。

+2

'(EQ?(車慢-LS)(汽車快速-LS))'似乎是錯誤的。它應該是'(eq?slow-ls fast-ls)'。用''(#f #f #f)' – Sylwester 2015-03-25 12:22:01

+0

試試看,這似乎是真的。我只是複製粘貼的代碼。我會更新!謝謝。 – 2015-03-25 12:46:23

1

在SRFI 1中有circular-list?謂詞。SRFI 1中循環列表的定義是:「循環列表是一個值,使得對於每個n> = 0,cdr^n(x)是一對。這意味着沒有結束的名單。第一對圓形列表不需要是循環的一部分。最終通過跟隨cdrs達到一個週期就足夠了。

SRFI 1對非圓列出這樣的描述:

(not (circular-list? x)) = (or (proper-list? x) (dotted-list? x)) 

SRFI 1是不是在R5RS本身,但我知道的所有實現配SRFI 1包括在內。請注意,如果srfi1在運行時中實現,則來自srfi 1的circular-list?謂詞可能比龜與兔算法的Scheme實現更快。基準你的實現選擇,以找出你的實現如何表現。

http://srfi.schemers.org/srfi-1/srfi-1.html#circular-list-p