检查列表是否为循环的过程(Scheme)

时间:2015-03-25 10:23:34

标签: list scheme r5rs cyclic

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

2 个答案:

答案 0 :(得分: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。

答案 1 :(得分: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