Bölüm 5.1: Dizgi Eşleştirme ve Sıkıştırma

Bölüm 5.1: Dizgi Eşleştirme ve Sıkıştırma · Çalışma Soruları
Kaba kuvvetKMP ve LPS tablosuBoyer-Moore ve HorspoolRabin-KarpRLELZW ve LZ78
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Çıktı Sorusu · Kaba Kuvvet

Soru 1: Kaç Karşılaştırma?

Dersteki kabaKuvvet metodu kabaKuvvet("abracacadabra", "cad") çağrısında hangi değeri döndürür ve toplam kaç karakter karşılaştırması yapar?

int kabaKuvvet(String t, String p) {
  int n = t.length(), m = p.length();
  for (int i = 0; i <= n - m; i++) {
    int j = 0;
    while (j < m &&
      t.charAt(i + j) == p.charAt(j))
      j++;
    if (j == m) return i;
  }
  return -1;
}
Cevabı göster

Dönüş: 6 · karşılaştırma: 11

  • s = 0, 1, 2, 3: ilk karakter (a, b, r, a) ≠ c → 4 × 1 = 4
  • s = 4: c = c, a = a, c ≠ d → 3
  • s = 5: a ≠ c → 1
  • s = 6: c, a, d eşleşir → 3; j == m olduğu için 6 döner
abracacadabra0123456789101112s=4cads=5cads=6cad

4 + 3 + 1 + 3 = 11. Uyuşmazlıkta öğrenilen bilgi atılır; örüntü her seferinde yalnızca 1 kayar.

Çoktan Seçmeli · Kaba Kuvvet

Soru 2: Döngü Sınırı Hatası

kabaKuvvet metodundaki i <= n - m koşulu yanlışlıkla i < n - m yazılırsa aşağıdaki çağrılardan hangisi yanlış sonuç (−1) döndürür?

C: n = 5, m = 2 için doğru kaymalar 0..3'tür; hatalı koşul yalnızca 0, 1, 2'yi dener. "em" yalnızca s = 3 = n − m konumunda geçtiği için bulunamaz. "le" s = 2'de olduğu için hâlâ bulunur.

Adım Adım Çalıştırma · Kaba Kuvvet

Soru 3: kabaKuvvet İzleme

kabaKuvvet("AABAABAAC", "AAC") hangi değeri döndürür, kaç karakter karşılaştırması yapılır?

AABAABAAC012345678AAC

n = 9, m = 3: geçerli kaymalar i = 0..6. Örüntü metnin altına i = 0 hizasında yerleşecek.

AABAABAAC012345678AAC

i = 0: 2 karakter eşleşti, t[2] = 'B' ≠ p[2] = 'C' → örüntü 1 kayar.

AABAABAAC012345678AAC

i = 1: 1 karakter eşleşti, t[2] = 'B' ≠ p[1] = 'A' → örüntü 1 kayar.

AABAABAAC012345678AAC

i = 2: t[2] = 'B' ≠ p[0] = 'A' → ilk karakterde uyuşmazlık, örüntü 1 kayar.

AABAABAAC012345678AAC

i = 3: 2 karakter eşleşti, t[5] = 'B' ≠ p[2] = 'C' → örüntü 1 kayar.

AABAABAAC012345678AAC

i = 4: 1 karakter eşleşti, t[5] = 'B' ≠ p[1] = 'A' → örüntü 1 kayar.

AABAABAAC012345678AAC

i = 5: t[5] = 'B' ≠ p[0] = 'A' → ilk karakterde uyuşmazlık, örüntü 1 kayar.

AABAABAAC012345678AAC

i = 6: A, A, C üçü de eşleşti; j = 3 = m olunca while döngüsü biter.

AABAABAAC012345678AAC

j == m → 6 döndürülür. Toplam 15 karşılaştırma; aynı A'lar farklı hizalarda tekrar tekrar okundu.

int kabaKuvvet(String t, String p) {
  int n = t.length(), m = p.length();
  for (int i = 0; i <= n - m; i++) {
    int j = 0;
    while (j < m &&
      t.charAt(i + j) == p.charAt(j))
      j++;
    if (j == m) return i;
  }
  return -1;
}

Çoktan Seçmeli · KMP

Soru 4: LPS Tanımı

lpsHesapla("aaaa") hangi diziyi döndürür?

A: lps[q], P[0..q]'nun kendisine eşit olmayan (uygun) ve aynı zamanda soneki olan en uzun önekidir. "aaaa" için bu "aaa" → 3. B dizginin kendisini de sayar; D ise yalnızca tek karakterlik öneki dener.

Adım Adım Çalıştırma · KMP

Soru 5: lpsHesapla İzleme

lpsHesapla("ababaca") hangi diziyi döndürür?

Pababaca0123456lps0

lps[0] = 0 her zaman (tek karakterin uygun öneki yok). k: o ana kadar eşleşen önek uzunluğu.

Pababaca0123456lps00

p[0] = 'a' ≠ p[1] = 'b' → k = 0 kalır, lps[1] = 0.

Pababaca0123456lps001

p[0] = 'a' = p[2] → k = 1, lps[2] = 1.

Pababaca0123456lps0012

p[1] = 'b' = p[3] → k = 2, lps[3] = 2.

Pababaca0123456lps00123

p[2] = 'a' = p[4] → k = 3, lps[4] = 3.

Pababaca0123456lps00123

p[3] = 'b' ≠ p[5] = 'c' → geri çekil: k = lps[2] = 1.

Pababaca0123456lps00123

p[1] = 'b' ≠ p[5] = 'c' → geri çekil: k = lps[0] = 0.

Pababaca0123456lps001230

p[0] = 'a' ≠ p[5] = 'c' → k = 0 kalır, lps[5] = 0.

Pababaca0123456lps0012301

p[0] = 'a' = p[6] → k = 1, lps[6] = 1.

Pababaca0123456lps0012301

Sonuç: lps = [0, 0, 1, 2, 3, 0, 1]. Toplam geri çekilme toplam artışı aşamaz → O(m).

int[] lpsHesapla(String p) {
  int m = p.length(), k = 0;
  int[] lps = new int[m];
  for (int q = 1; q < m; q++) {
    while (k > 0 &&
      p.charAt(k) != p.charAt(q))
      k = lps[k - 1];
    if (p.charAt(k) == p.charAt(q))
      k++;
    lps[q] = k;
  }
  return lps;
}

Çoktan Seçmeli · KMP

Soru 6: Uyuşmazlıkta Geri Çekilme

Örüntü "abcabd" için lps = [0, 0, 0, 1, 2, 0]. KMP aramasında metinle "abcab" eşleşmişken (q = 5) sıradaki metin karakteri d değil. q hangi değeri alır ve örüntü kaç konum kaymış olur?

D: q = lps[q − 1] = lps[4] = 2, çünkü "ab" eşleşen "abcab"ın hem öneki hem sonekidir; kayma 5 − 2 = 3. B, lps[q] (lps[5] = 0) kullanma hatasıdır. Metin işaretçisi i geri gitmez; "ab" yeniden karşılaştırılmaz.

Çıktı Sorusu · KMP

Soru 7: Üç Algoritma, Bir Metin

Metin "gel de geleyim", örüntü "geleyim". Kaba kuvvet, KMP ve Boyer-Moore (yalnızca kötü karakter kuralı) ilk eşleşmeyi bulana kadar kaçar karakter karşılaştırması yapar? Eşleşme hangi konumdadır?

Cevabı göster

Eşleşme s = 7. Karşılaştırmalar: kaba kuvvet 17, KMP 15, Boyer-Moore 8.

  • Kaba kuvvet: s = 0'da "gel" eşleşir, '␣' ≠ 'e' (4); s = 1..6 ilk karakterde biter (6); s = 7'de 7 → 17.
  • KMP (lps hep 0): "gel" (3), '␣' önce p[3] sonra p[0] ile (2), d, e, ␣ (3), geleyim (7) → 15. Metin hiç geri okunmaz.
  • Boyer-Moore: s = 0'da sağdan ilk karşılaştırma t[6] = '␣' ≠ 'm'; ␣ örüntüde yok → 7 kaydır; s = 7'de 7 eşleşme → 8.
gel␣de␣geleyim012345678910111213BM 1geleyimBM 2geleyim

Çoktan Seçmeli · KMP

Soru 8: KMP Neden Doğrusal?

KMP aramasında while döngüsündeki geri çekilmelerin (q = lps[q - 1]) toplam sayısı neden n'yi aşamaz?

B: Amortize argüman: q her adımda en çok 1 artar (toplam ≤ n), her geri çekilme onu en az 1 azaltır ve q ≥ 0 kalır; bu yüzden toplam geri çekilme ≤ n, arama O(n). C yanlıştır: KMP'de i hiç geri gitmez; A da yanlıştır: lps değerleri m − 1'e kadar çıkabilir.

Çoktan Seçmeli · Boyer-Moore

Soru 9: max(1, …) Neden Var?

Boyer-Moore'da kaydırma s += Math.max(1, j - son[c]) yerine s += j - son[c] yazılırsa ne olur?

A: Örneğin "abacab"da c = a için son = 4'tür; uyuşmazlık j = 3'te çıkarsa 3 − 4 = −1 olur. max(1, …) en az 1 ilerlemeyi garanti eder; yoksa sonsuz döngü ya da geri gitme olur. B yanlıştır: j + 1 kaydırma güvenlidir, çünkü c'yi içeren hiçbir hiza eşleşemez.

Adım Adım Çalıştırma · Boyer-Moore

Soru 10: boyerMoore İzleme

boyerMoore("KARTAL KALKAR", "KALKAR") hangi değeri döndürür?

KARTAL␣KALKAR0123456789101112KALKAR

n = 13, m = 6. Son görülme: K = 3, A = 4, L = 2, R = 5, diğerleri −1. Karşılaştırma sağdan sola yapılacak.

KARTAL␣KALKAR0123456789101112KALKAR

s = 0: p[5] = 'R' ≠ t[5] = 'L'. Kötü karakter: 'L'.

KARTAL␣KALKAR0123456789101112KALKAR

son['L'] = 2 → max(1, 5 − 2) = 3; s = 3.

KARTAL␣KALKAR0123456789101112KALKAR

s = 3: p[5] = 'R' ≠ t[8] = 'A'. Kötü karakter: 'A'.

KARTAL␣KALKAR0123456789101112KALKAR

son['A'] = 4 → max(1, 5 − 4) = 1; s = 4.

KARTAL␣KALKAR0123456789101112KALKAR

s = 4: p[5] = 'R' ≠ t[9] = 'L'. Kötü karakter: 'L'.

KARTAL␣KALKAR0123456789101112KALKAR

son['L'] = 2 → max(1, 5 − 2) = 3; s = 7.

KARTAL␣KALKAR0123456789101112KALKAR

s = 7: R, A, K, L, A, K sağdan sola eşleşti, j = −1.

KARTAL␣KALKAR0123456789101112KALKAR

j < 0 → 7 döndürülür. 4 hiza, toplam 9 karşılaştırma (kaba kuvvet 8 hiza dener).

int boyerMoore(String t, String p) {
  int n = t.length(), m = p.length();
  int[] son = sonGorulme(p);
  int s = 0;
  while (s <= n - m) {
    int j = m - 1;
    while (j >= 0 &&
      p.charAt(j) == t.charAt(s + j))
      j--;
    if (j < 0) return s;
    s += Math.max(1,
      j - son[t.charAt(s + j)]);
  }
  return -1;
}

Çıktı Sorusu · Boyer-Moore

Soru 11: Horspool Kaydırma Tablosu

"BARBER" örüntüsü için Horspool kaydırma tablosunu kayd[c] = m − 1 − (c'nin P[0..m−2] içindeki en sağ konumu), yoksa m kuralıyla kurun. Hizanın son karakterinin altındaki metin karakteri B, R ve X olursa örüntü kaçar kaydırılır?

PBARBER012345
Cevabı göster

m = 6; tabloya yalnızca P[0..4] = B A R B E katılır:

cBAREdiğer
kayd[c]5 − 3 = 25 − 1 = 45 − 2 = 35 − 4 = 16

B → 2, R → 3, X → 6. Son karakter (R, indis 5) tabloya katılmaz; R yine de indis 2'de geçtiği için 3 kaydırır. Kaydırma, uyuşmazlığın nerede olduğuna bakmaz; hep hizanın son karakterine göre yapılır.

Çıktı Sorusu · Rabin-Karp

Soru 12: Kayan Hash

Taban B = 10, Q = 11, karakterler rakam; T = "26535", m = 3. h("265") = 265 mod 11 = 1 ve Bm−1 mod Q = 100 mod 11 = 1'dir. Kaydırma formülü hs+1 = (B · (hs − t[s] · Bm−1) + t[s+m]) mod Q ile h("653") ve h("535")'i bulun.

T2653501234
Cevabı göster
  • h("653") = (10 · (1 − 2 · 1) + 3) mod 11 = (−7) mod 11 = 4 ✓ (653 = 59 · 11 + 4)
  • h("535") = (10 · (4 − 6 · 1) + 5) mod 11 = (−15) mod 11 = 7 ✓ (535 = 48 · 11 + 7)

Her yeni pencere O(1)'de: çıkan rakam düşülür, kalanlar bir basamak sola kayar, giren rakam eklenir. Ara sonuç negatif çıkabilir; Java'da % negatif verdiği için if (th < 0) th += Q gerekir.

Çoktan Seçmeli · Rabin-Karp

Soru 13: Sahte Eşleşme

Oyuncak hash: harf değerlerinin toplamı (a = 1, b = 2, c = 3, d = 4). "adcb" metninde "bc" (hash 5) aranıyor. Hangi pencereler sahte eşleşme (spurious hit) olur?

D: Pencereler "ad" = 5, "dc" = 7, "cb" = 5. İki pencerenin hash'i örüntününkine eşittir ama karakterleri farklıdır; doğrulama ikisini de reddeder ve metinde "bc" yoktur. Toplam hash sıraya duyarsızdır ("cb" de 5 verir); bu yüzden konum ağırlıklı polinom hash kullanılır.

Çoktan Seçmeli · Rabin-Karp

Soru 14: Çok Sayıda Örüntü

Aynı uzunlukta 500 farklı virüs imzası bir dosyada tek geçişte aranacak. Hangi yaklaşım en uygundur?

B: Pencere hash'i O(1)'de güncellenir ve HashSet'te O(1) ortalamayla aranır; bulunursa doğrulanır → beklenen O(n + k · m). A ve D dosyayı k kez tarar; C ise imzaları birleştirince hiçbir imzayı tek başına bulmaz.

Çoktan Seçmeli · RLE

Soru 15: RLE Ne Zaman Büyütür?

rleSikistir aşağıdaki girdilerden hangisinin çıktısını girdiden uzun yapar?

D: Hiç ardışık tekrar yok; her karakter "1" + karakter olarak yazılır: 8 → 16 karakter (iki kat). Diğerleri küçülür: "5a5b" (10 → 4), "4a1b4a" (9 → 6), "11x1y" (12 → 5). RLE yalnızca ardışık tekrarı yakalar; "abab…" gibi tekrar eden dizgileri LZW yakalar.

Adım Adım Çalıştırma · LZW

Soru 16: lzw İzleme

Başlangıç sözlüğü A = 0, B = 1 iken lzw("BABAABAAA") hangi kodları üretir?

BABAABAAAskoddizgiçıktı: —

Sözlük tek karakterlerle başlar: A = 0, B = 1; yeni dizgiler 2'den numaralanır. w = "".

BABAABAAAskoddizgiçıktı: —

"B" sözlükte (1) → w = "B"; daha uzun eşleşme aranır.

BABAABAAAskoddizgi2BAçıktı: 1

"BA" yok → w = "B" kodu 1 çıktıya; "BA" = 2 eklenir; w = "A".

BABAABAAAskoddizgi2BA3ABçıktı: 1 0

"AB" yok → w = "A" kodu 0 çıktıya; "AB" = 3 eklenir; w = "B".

BABAABAAAskoddizgi2BA3ABçıktı: 1 0

"BA" sözlükte (2) → w = "BA"; daha uzun eşleşme aranır.

BABAABAAAskoddizgi2BA3AB4BAAçıktı: 1 0 2

"BAA" yok → w = "BA" kodu 2 çıktıya; "BAA" = 4 eklenir; w = "A".

BABAABAAAskoddizgi2BA3AB4BAAçıktı: 1 0 2

"AB" sözlükte (3) → w = "AB"; daha uzun eşleşme aranır.

BABAABAAAskoddizgi2BA3AB4BAA5ABAçıktı: 1 0 2 3

"ABA" yok → w = "AB" kodu 3 çıktıya; "ABA" = 5 eklenir; w = "A".

BABAABAAAskoddizgi2BA3AB4BAA5ABA6AAçıktı: 1 0 2 3 0

"AA" yok → w = "A" kodu 0 çıktıya; "AA" = 6 eklenir; w = "A".

BABAABAAAskoddizgi2BA3AB4BAA5ABA6AAçıktı: 1 0 2 3 0

"AA" sözlükte (6) → w = "AA"; daha uzun eşleşme aranır.

BABAABAAAskoddizgi2BA3AB4BAA5ABA6AAçıktı: 1 0 2 3 0 6

Döngü bitti; kalan w = "AA" kodu 6 eklenir. Çıktı: 1 0 2 3 0 6 (9 sembol → 6 kod).

List<Integer> lzw(String s) {
  Map<String, Integer> sozluk = ilkSozluk(s);
  String w = "";
  List<Integer> kod = new ArrayList<>();
  for (char c : s.toCharArray()) {
    String wc = w + c;
    if (sozluk.containsKey(wc)) {
      w = wc;
    } else {
      kod.add(sozluk.get(w));
      sozluk.put(wc, sozluk.size());
      w = "" + c;
    }
  }
  if (!w.isEmpty()) kod.add(sozluk.get(w));
  return kod;
}

Çıktı Sorusu · LZW

Soru 17: LZW Açma

Başlangıç sözlüğü A = 0, B = 1, C = 2. LZW ile sıkıştırılmış 0 1 3 2 4 7 kod dizisini açın. Hangi kodda açıcı "henüz tanımlanmamış kod" durumuyla karşılaşır?

Cevabı göster
kodyazılansözlüğe eklenen
0A—
1B3 = AB
3AB4 = BA
2C5 = ABC
4BA6 = CB
7BAB7 = BAB (özel durum)

Sonuç: ABABCBABAB. 7 okunduğunda açıcının sözlüğü 6'ya kadardır: e = w + w[0] = "BA" + "B" = "BAB". Kontrol: lzw("ABABCBABAB") yine 0 1 3 2 4 7 verir.

Çoktan Seçmeli · LZW

Soru 18: LZ78 Çıktısı

Sözlüğü boş başlayan LZ78, "abababa" dizgisini hangi (indis, karakter) çiftlerine dönüştürür?

C: "a" → (0, a), sözlüğe 1 = a; "b" → (0, b), 2 = b; "ab": a var (1), ab yok → (1, b), 3 = ab; "aba": ab var (3), aba yok → (3, a), 4 = aba. LZW'nin farkı sözlüğü tüm tek karakterlerle başlatmasıdır; böylece çıktıda karakter yazmaya gerek kalmaz.

Klasik Soru · Karşılaştırma

Soru 19: Senaryoya Göre Algoritma

Her senaryo için dersteki dizgi eşleştirme algoritmalarından birini seçin ve gerekçesini yazın:
(a) Ağdan akan ve geri okunamayan veride, en kötü durumu sınırlı bir arama gerekiyor.
(b) Bir editörde uzun bir İngilizce metinde 12 harfli bir kelime aranıyor.
(c) Bir belgede aynı uzunlukta binlerce cümle (intihal kontrolü) aranıyor.

Cevabı göster
  • (a) KMP: metin işaretçisi asla geri gitmez (akışa uygun); en kötü durumda da O(n + m).
  • (b) Boyer-Moore / Horspool: uzun örüntü ve geniş alfabede kötü karakter kuralı neredeyse m karakter atlar; pratikte en hızlısı, en iyi O(n/m).
  • (c) Rabin-Karp: örüntü hash'leri bir kümeye konur, her pencere O(1)'de güncellenip kümede aranır; beklenen O(n + k · m).

Kaba kuvvet ön işleme istemez ve kısa örüntüde yeterlidir, ama en kötü durumu O(n · m)'dir.

Son

Bölüm 5.1: Dizgi Eşleştirme ve Sıkıştırma: Çalışma Soruları
Konu anlatımı: Dizgi Algoritmaları sunumu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.