フロイドの循環検出法 external_link

リスト構造上にある循環路を検出する方法。
※ハッシュ表を使う方法もある。 → 入門データ構造とアルゴリズム p383 Q14ー9

考え方

循環の検出

  1. ノード0をスタート地点とし、兎ポインタが2つ移動する間に、亀ポインタを1つ移動させる。
CycleDetection-0001.jpg
CycleDetection-0002.jpg
  1. 兎が1周した時、亀はまだ半周。
CycleDetection-0003.jpg
  1. 亀が1周すると兎は2周し亀と出会う。
    この出会いが「循環」であることを証明する。
    ※「循環」でなければ、兎は亀に出会うことなく出口に到着する。
CycleDetection-0004.jpg

循環路の入り口検出

  1. ノード0を引っ張り出す。このとき循環路の長さは変わらないものとすると、兎と亀はノード6で出会う。
CycleDetection-0005.jpg
  1. 兎はそのままにして亀をノード0へ戻す。そして、今度は兎と亀を同じ速度(1つずつ)で移動させる。
    兎と亀は循環路の入り口で出会う。
    今回は1ノードだけ引っ張り出したがいくつ引っ張り出しても結果は同じである。
CycleDetection-0006.jpg
CycleDetection-0007.jpg
CycleDetection-0008.jpg

擬似コード

FindCycle(LIST) { head = 0 turtle = LIST.HEAD rabbit = LIST.HEAD while (The rabbit has not arrived at the end of the list) { turtle = turtle.NEXT rabbit = rabbit.NEXT rabbit = rabbit.NEXT if (turtle == rabbit) { // get cycle entrance turtle = LIST.HEAD while (true) { if (turtle = rabbit) return rabbit turtle = turtle.NEXT rabbit = rabbit.NEXT } } } return no-cycle }

🌏 Map

same layerlower layer