开始想的解题思路就是判断第一个序对是否在后面每个序对的cdr中,是的话就是个环,但是这个有个问题,如果一个序列,除过第一个元素,后面的元素组成一个环,这个就变成死循环了。
#lang R5RS
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
(define (make-cycle x)
(set-cdr! (last-pair x) x)
x)
(define (element-cdr-of-set? x set)
(cond ((not (pair? set)) #false)
((eq? x (cdr set)) #true)
(else (element-cdr-of-set? x (cdr set)))))
(define (adjoin-set x set)
(cons x set))
(define (is-cycle? x)
(cond ((not (pair? x)) #false)
((element-cdr-of-set? x (cdr x)) #true)
(else (is-cycle? (cdr x)))))
(define z (make-cycle (list 'a 'b 'c)))
(display z)
(newline)
(display (is-cycle? z))
(newline)
(define z1 (list 'a 'b 'c))
(display z1)
(newline)
(display (is-cycle? z1))
运行结果
#0=(a b c . #0#)
#t
(a b c)
#f
于是换用第二种思路,也叫“快慢指针”,用两个变量一起遍历序列,一个一次遍历两个,一个一次遍历一个,如果两个变量相遇,就判定是一个环,如果遍历两个的那个变量先到达终点,则不是一个环。
下面是这种思路的代码
#lang R5RS
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
(define (make-cycle x)
(set-cdr! (last-pair x) x)
x)
(define (is-cycle? x)
(define (is-cycle-two? x1 x2)
(cond ((not (pair? x2)) #false)
((not (pair? (cdr x2))) #false)
((eq? x1 x2) #true)
(else (is-cycle-two? (cdr x1) (cddr x2)))))
(if (not (pair? x)) #false
(is-cycle-two? x (cdr x))))
(define z (make-cycle (list 'a 'b 'c)))
(display z)
(newline)
(display (is-cycle? z))
(newline)
(define z1 (list 'a 'b 'c))
(display z1)
(newline)
(display (is-cycle? z1))
运行结果
#0=(a b c . #0#)
#t
(a b c)
#f