Дозвольте спробувати уточнити алгоритм виявлення циклу, який надається на http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare своїми власними словами.
Як це працює
Будемо мати черепаху та зайця (назва покажчиків), що вказують на початок списку циклом, як на схемі вище.
Давайте припустимо, що якщо ми перемістимо черепаху 1 крок за часом, і займемося за 2 кроки одночасно, вони зрештою зустрінуться в точці. Покажемо, що насамперед ця гіпотеза правдива.
На малюнку зображено список із циклом. Цикл має довжину, n
і ми спочатку m
крокуємо від циклу. Скажімо також, що місце зустрічі знаходиться в k
кроці від початку циклу, і черепаха та заєць зустрічаються, коли черепаха зробила i
загальні кроки. (Заєць взяв би2i
загальні кроки.)
Наступні 2 умови повинні виконуватися:
1) i = m + p * n + k
2) 2i = m + q * n + k
Перший говорить про те, що черепаха рухає i
кроки і в цих i
кроках спочатку потрапляє в цикл. Потім він проходить через цикл p
разів для деякого додатного числа p
. Нарешті це переходитьk
більше вузлів, поки не зустріне зайця.
Подібне стосується зайців. Він переміщує 2i
кроки і в цих 2i
кроках спочатку потрапляє в цикл. Потім він проходить через цикл q
разів для деякого додатного числа q
. Нарешті він перебирає k
більше вузлів, поки не зустріне черепаху.
Оскільки заєць подорожує з подвійною швидкістю черепахи, і час є постійним для обох, коли вони досягають місця зустрічі.
Таким чином, використовуючи просте відношення швидкості, часу та відстані,
2 ( m + p * n + k ) = m + q * n + k
=> 2m + 2pn + 2k = m + nq + k
=> m + k = ( q - 2p ) n
Серед m, n, k, p, q перші два - це властивості даного списку. Якщо ми можемо показати, що існує принаймні один набір значень для k, q, p, що робить це рівняння правдивим, ми показуємо, що гіпотеза правильна.
Один такий набір рішень такий:
p = 0
q = m
k = m n - m
Ми можемо перевірити, що ці значення працюють наступним чином:
m + k = ( q - 2p ) n
=> m + mn - m = ( m - 2*0) n
=> mn = mn.
Для цього набору, i
є
i = m + p n + k
=> m + 0 * n + mn - m = mn.
Звичайно, ви повинні бачити, що це не обов'язково найменший i можливий. Іншими словами, черепаха та заєць, можливо, вже зустрічалися раніше. Однак, оскільки ми показуємо, що вони зустрічаються в якийсь момент хоча б раз, можна сказати, що гіпотеза правильна. Тож їм доведеться зустрітися, якщо ми перемістимо один з них 1 крок, а другий - 2 кроки за раз.
Тепер ми можемо перейти до другої частини алгоритму, яка полягає в тому, як знайти початок циклу.
Цикл Початок
Як тільки черепаха і заєць зустрічаються, давайте повернемо черепаху на початок списку і збережемо зайця там, де вони зустрілися (що знаходиться в k кроках від початку циклу).
Гіпотеза полягає в тому, що якщо ми дозволимо їм рухатися з однаковою швидкістю (1 крок для обох), перший раз, коли вони знову зустрінуться, буде цикл початку.
Доведемо цю гіпотезу.
Спочатку припустимо, що якийсь оракул говорить нам, що таке m.
Тоді, якщо ми дозволимо їм рухатися кроками m + k, черепаха повинна була б дійти до точки, з якою вони зустрілися спочатку (k кроки від початку циклу - див. На малюнку).
Раніше ми це показували m + k = (q - 2p) n
.
Оскільки кроки m + k є кратною довжині циклу n, заєць у середній час пройшов би цикл (q-2p) разів і повернувся б до тієї ж точки (k кроків від початку циклу).
Тепер, замість того, щоб дозволити їм рухатися m + k кроками, якщо ми дозволимо їм рухатись лише m кроками, черепаха приїде на початку циклу. Заєць не матиме крок від завершення обертання (q-2p). Оскільки він почав k кроки перед початком циклу, заєць повинен був прибути на початку циклу.
Як результат, це пояснює, що їм доведеться зустрітися на початку циклу після деякої кількості кроків вперше (дуже перший раз, тому що черепаха щойно приїхала в цикл після m кроків, і вона ніколи не може побачити зайця, який вже був у цикл).
Тепер ми знаємо, що кількість кроків, необхідних нам для їх переміщення, поки вони не зустрінуться, виявляється відстань від початку списку до початку циклу, m. Звичайно, алгоритму не потрібно знати, що таке m. Він просто перемістить і черепаху, і зайця, крок за часом, поки вони не зустрінуться. Місцем зустрічі має бути початок циклу, а кількість кроків має бути відстань (м) до початку циклу. Припускаючи, що ми знаємо довжину списку, ми можемо також обчислити довжину циклу віднімання m від довжини списку.