循環リストの判定
30分プログラム、その606。循環リストの判定をしてみよう。
たしか昔、Common Lispの勉強をしてたときに判定アルゴリズムを読んだ気がする。
おっと、これだこれ。
循環リストのチェックは「うさぎとかめ」のアルゴリズムを使うと簡単です。「うさぎ」と「かめ」はリストをたどる変数として定義します。うさぎは cdr を 2 回適用して進みますが、かめは cdr を 1 回適用して進みます。うさぎがリストの終端に到達すれば、リストは循環していないことがわかります。うさぎがかめに追いつけば、リストは循環していると判断できます。プログラムは次のようになります。
使い方
gosh> (define xs (let1 a '(1) (set-cdr! a a) a)) gosh> xs #0=(1 . #0#) gosh> (circular? xs) #t gosh> (circular? '(1 2 3)) #f
ソースコード
#! /opt/local/bin/gosh ;; -*- mode:scheme; coding:utf-8 -*- ;; ;; circular.scm - ;; ;; Copyright(C) 2009 by mzp ;; Author: MIZUNO Hiroki / mzpppp at gmail dot com ;; http://howdyworld.org ;; ;; Timestamp: 2009/06/19 21:00:07 ;; ;; This program is free software; you can redistribute it and/or ;; modify it under MIT Lincence. ;; (define (circular? xs) (define (iter xs ys) (cond [(or (null? xs) (null? ys)) #f] [(eq? (car xs) (car ys)) #t] [else (iter (cdr xs) (cddr ys))])) (iter xs (cdr xs))) (define xs (let1 a '(1) (set-cdr! a a) a)) (circular? xs) (circular? '(1 2 3))