1

是否有一个内置程序来检查一个列表是否在 Scheme (R5RS) 中是循环的?什么时候列表是循环的(根据定义)?我试图找到一些程序来检查这一点,以及它是如何实现的,但我一直找不到。

4

2 回答 2

2

如果尾部(最后一个元素)的 指向列表的头部,则列表根据定义是循环的。cdr但是,您也可以有一个循环列表,其中cdr尾部的 指向列表中的任意元素。检测循环列表的一个很好的算法是龟兔算法。此页面提供了一个示例实现。

代码如下(归功于上面链接页面的作者):

编辑:我修改了代码,因为它包含 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。

于 2015-03-25T10:31:01.607 回答
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 在运行时实现,则circular-list?来自 srfi 1 的谓词可能比龟兔算法的 Scheme 实现更快。对您选择的实现进行基准测试,以了解您的实现的行为方式。

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

于 2015-03-25T18:20:43.390 回答