Floyd's Cycle Finding Algoritması (Tortoise and Hare)

Floyd'un Döngü Bulma Algoritması, bağlı listelerdeki döngüleri tespit etmek için kullanılan verimli bir algoritmadır. 'Kaplumbağa ve Tavşan' algoritması olarak da bilinir. Biri yavaş (kaplumbağa), diğeri hızlı (tavşan) hareket eden iki işaretçi kullanarak, döngü varsa bu iki işaretçinin mutlaka bir noktada buluşacağı prensibine dayanır.

Avantajlar

  • Sabit bellek kullanımı (O(1) uzay karmaşıklığı)
  • Doğrusal zaman karmaşıklığı (O(n))
  • Döngünün başlangıç noktasını ve uzunluğunu tespit edebilir
  • Uygulaması basittir ve minimum işaretçi kullanır

Dezavantajlar

  • Yalnızca bağlı listeler veya işaretçi temelli veri yapıları için tasarlanmıştır
  • Algoritma, durum makinesi veya otomat tabanlı algoritmalardan daha az sezgiseldir
  • Hash tablosu kullanarak çözme yaklaşımından biraz daha yavaş olabilir

İnteraktif Demo

Floyd's Cycle Finding algoritmasını test edin. Aşağıdaki dizide her sayı, bir sonraki indeksi temsil eder (dizideki bir değer 3 ise, o pozisyonda 3. indekse bir bağlantı olduğunu gösterir). Döngü oluşturmak için, aynı indekse birden fazla bağlantı olmalıdır.

Her sayı, o indeksten bağlanan bir sonraki indeksi temsil eder. Sayılar 0 ile (dizi uzunluğu - 1) arasında olmalıdır.

1
0
3
1
4
2
2
3
2
4
01
13
24
32
42

Sonuç

Döngü tespit edilemedi.

Kod Örnekleri

Floyd's Cycle Finding algoritmasının farklı programlama dillerindeki implementasyonları.

Floyd's Cycle Finding - TypeScript
1function floydCycleFinding(arr: T[]): { cycleExists: boolean; cycleStart?: number; cycleLength?: number } {
2 // Boş dizi kontrolü
3 if (arr.length === 0) {
4 return { cycleExists: false };
5 }
6
7 let tortoise = 0; // Yavaş hareket eden işaretçi (kaplumbağa)
8 let hare = 0; // Hızlı hareket eden işaretçi (tavşan)
9
10 // Faz 1: Döngünün varlığını tespit et
11 do {
12 // Kaplumbağa bir adım, tavşan iki adım ilerler
13 tortoise = getNextIndex(arr, tortoise);
14 hare = getNextIndex(arr, getNextIndex(arr, hare));
15
16 // Dizi sınırlarını aşma kontrolü
17 if (tortoise === -1 || hare === -1) {
18 return { cycleExists: false };
19 }
20
21 } while (tortoise !== hare);
22
23 // Buraya ulaşıldıysa, döngü var demektir
24
25 // Faz 2: Döngünün başlangıç noktasını bul
26 tortoise = 0;
27 while (tortoise !== hare) {
28 tortoise = getNextIndex(arr, tortoise);
29 hare = getNextIndex(arr, hare);
30 }
31
32 // Döngünün uzunluğunu hesapla
33 let cycleLength = 1;
34 hare = getNextIndex(arr, tortoise);
35 while (tortoise !== hare) {
36 hare = getNextIndex(arr, hare);
37 cycleLength++;
38 }
39
40 return {
41 cycleExists: true,
42 cycleStart: tortoise,
43 cycleLength: cycleLength
44 };
45}

Algoritma Nasıl Çalışır?

Floyd'un Döngü Bulma Algoritması iki aşamada çalışır:

Faz 1: Döngünün Varlığını Tespit Etme

  • İki işaretçi kullanılır: tortoise (kaplumbağa) ve hare (tavşan).
  • Her adımda kaplumbağa bir adım, tavşan iki adım ilerler.
  • Eğer döngü varsa, tavşan kaplumbağayı mutlaka yakalar (aynı noktada buluşurlar).
  • Eğer tavşan listenin sonuna ulaşırsa (null/undefined), döngü yoktur.

Faz 2: Döngünün Başlangıç Noktasını Bulma

  • Kaplumbağa başlangıç noktasına (0 indeksine) geri döner.
  • Tavşan Faz 1'deki buluşma noktasında kalır.
  • Şimdi her ikisi de aynı hızda (her adımda bir) ilerler.
  • Buluştukları nokta, döngünün başlangıç noktasıdır.

Faz 3: Döngünün Uzunluğunu Hesaplama

  • Döngünün başlangıç noktasından itibaren bir işaretçi ilerletilir.
  • Başlangıç noktasına geri dönene kadar adımlar sayılır.
  • Bu sayı, döngünün uzunluğunu verir.

Matematiksel Sezgi

Bu algoritmanın çalışmasının arkasındaki matematiksel sezgi şudur: Eğer kaplumbağa ve tavşan döngü içerisinde buluşursa, kaplumbağa 'k' adım atmışsa, tavşan '2k' adım atmıştır. Buluşma noktasından döngünün başlangıcına olan mesafe, başlangıç noktasından döngü başlangıcına olan mesafeye eşittir. Bu, döngünün başlangıcını bulmak için ikinci fazda iki işaretçinin neden aynı noktada buluştuğunu açıklar.