Bölüm 5: Dizgi Algoritmaları (2)

Algoritmalar
Sözlüksel sıralamaRadix sıralamaDüzenli ifadelerSonlu durum makineleri Levenshtein mesafesiEn uzun ortak alt diziSonek dizisiBurrows–Wheeler dönüşümü
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Sıralama

Dizgileri sözlüksel sırayla karşılaştırmak; LSD ve MSD radix sıralamayı adım adım uygulamak ve O(W · (N + R)) maliyetini açıklamak.

Ayrıştırma

Düzenli ifadeler yazıp okumak; bir sonlu durum makinesini (DFA) tasarlamak, çizmek ve bir girdi üzerinde çalıştırmak.

Benzerlik

Levenshtein mesafesini ve en uzun ortak alt diziyi (LCS) dinamik programlama tablosuyla hesaplamak ve geri izlemek.

Dönüşüm

Sonek dizisini kurmak ve aramada kullanmak; Burrows–Wheeler dönüşümünü hesaplamak ve tersine çevirmek.

Giriş

Dizgi Algoritmaları: Dört Problem Ailesi

Bu sunum, dizgiler (string) üzerinde çalışan dört algoritma ailesini ele alır:

Sıralama (String Sorting)Sözlüksel sıralama (lexicographic order): dizgiler karakter kodları karşılaştırılarak sözlükteki gibi dizilir. Radix sıralama: karşılaştırma yapmadan, her karakteri bir basamak gibi kullanarak gruplar.
Ayrıştırma (Parsing)Düzenli ifadeler (regular expressions): bir arama örüntüsünü tanımlayan karakter dizisi. Sonlu durum makineleri (FSM): girdiyi karakter karakter okuyup durum değiştiren otomatlar.
Benzerlik (Similarity)Levenshtein mesafesi: bir dizgiyi diğerine dönüştüren en az tek karakterlik düzenleme sayısı. LCS: göreli sırası korunan, ardışık olması gerekmeyen en uzun ortak alt dizi.
Dönüşüm (Transformation)Sonek dizisi (suffix array): tüm soneklerin sıralı başlangıç indisleri. Burrows–Wheeler dönüşümü (BWT): döndürmelerin sıralanmasıyla elde edilen, tersine çevrilebilir dönüşüm; bzip2'nin ön adımı.

Dizgi Sıralama

Sözlüksel Sıralama (Lexicographic Order)

  • Sözlüksel (alfabetik) sıralama (lexicographic order), öğeleri karakterlerin alfabedeki ya da kod tablosundaki konumlarına göre dizer.
  • Karşılaştırma ilk karakterlerle başlar; eşitse bir sonraki karakterlere bakılır.
  • İlk farklı karakter sonucu belirler: "apple" < "banana", çünkü 'a' < 'b'.
  • Bir dizgi tükenirse kısa olan (önek) önce gelir: "car" < "cart".
KarşılaştırmaKarar veren
apple · bananaa < b (1. karakter)
apple · apricotp < r (3. karakter)
car · cart"car" tükendi
Zebra · apple'Z' (90) < 'a' (97)
Dikkat: Bilgisayar "alfabe" olarak karakter kodlarını (ASCII / Unicode) kullanır: tüm büyük harfler küçük harflerden önce gelir; ç, ğ, ı, ö, ş, ü ise z'den sonra gelir. Türkçe sözlük sırası için java.text.Collator kullanılır.

Dizgi Sıralama · Kodu adım adım çalıştır

Örnek: "apple" ve "apricot" Karşılaştırması

abappleapricot0123456

karsilastir("apple", "apricot") çağrıldı. Sonuç negatifse a önce, pozitifse b önce gelir (String.compareTo da böyle çalışır).

abappleapricot0123456

Kısa olanın uzunluğu kadar karakter karşılaştırılabilir: n = min(5, 7) = 5.

abappleapricot0123456k

k = 0 < n: döngü sürer; 1. karakterlere bakılacak.

abappleapricot0123456k'a' = 97'a' = 97

x = 'a' (97), y = 'a' (97) okundu.

abappleapricot0123456k'a' = 97'a' = 97

'a' == 'a': karakterler eşit, karar verilemez; sonraki karaktere geçilir.

abappleapricot0123456k

k = 1 < n: döngü sürer; 2. karakterlere bakılacak.

abappleapricot0123456k'p' = 112'p' = 112

x = 'p' (112), y = 'p' (112) okundu.

abappleapricot0123456k'p' = 112'p' = 112

'p' == 'p': karakterler eşit, karar verilemez; sonraki karaktere geçilir.

abappleapricot0123456k

k = 2 < n: döngü sürer; 3. karakterlere bakılacak.

abappleapricot0123456k'p' = 112'r' = 114

x = 'p' (112), y = 'r' (114) okundu.

abappleapricot0123456k'p' = 112'r' = 114

'p' ≠ 'r': ilk farklı karakter bulundu (3. karakter).

abappleapricot0123456k'p' = 112'r' = 114

return 112 − 114 = −2 < 0 → apple, apricot'tan önce gelir. Kalan karakterlere hiç bakılmaz.

int karsilastir(String a, String b) {
  int n = Math.min(a.length(), b.length());
  for (int k = 0; k < n; k++) {
    char x = a.charAt(k), y = b.charAt(k);
    if (x != y)
      return x - y;   // ilk farklı karakter
  }
  return a.length() - b.length();
}

Dizgi Sıralama

Sözlüksel Sıra: Kelimeler ve Sayılar

Kelime 1Kelime 2EDUCATIVEEDUCATED✓✓✓✓✓✓✗·'E' (69) < 'I' (73)→ Kelime 2 önce
sayısalsözlüksel23571113171923291113171922329357
  • Sayılar dizgi olarak sıralanırsa soldan sağa karakter karşılaştırılır: "11" < "2", çünkü '1' < '2'. Benzer şekilde 123, 45, 6, 789 sözlüksel olarak bu sıradadır.
  • Sayısal sıra isteniyorsa sayılar tamsayıya çevrilmeli ya da soldan sıfırla aynı uzunluğa getirilmelidir ("02" < "11").

Dizgi Sıralama

Karşılaştırmalı Dizgi Sıralama

void sozlukselSirala(String[] a) {
  int n = a.length;
  for (int i = 0; i < n - 1; i++)
    for (int j = i + 1; j < n; j++)
      if (a[i].compareTo(a[j]) > 0) {
        String gecici = a[i];
        a[i] = a[j];
        a[j] = gecici;
      }
}
  • Her konuma, kalanların sözlükçe en küçüğü yer değiştirmelerle getirilir.
  • compareTo en fazla W karakter okur (W: en uzun dizgi).
  • Zaman: O(N²) karşılaştırma × O(W) = O(N² · W).
  • Birleştirme sıralaması ile O(N log N) karşılaştırma → O(W · N log N).
GirdiÇıktı
eabcdf, abcde, bcdea, cdeab, deabcgabcde, bcdea, cdeab, deabcg, eabcdf
banana, orange, grape, apple, kiwiapple, banana, grape, kiwi, orange

Karşılaştırmalı sıralamalar en az Ω(N log N) karşılaştırma yapar. Radix sıralama karşılaştırma yapmadığı için bu alt sınıra tabi değildir.

Dizgi Sıralama

Tabana Göre Sıralama (Radix Sort)

  • Tabana göre sıralama (radix sort), karşılaştırmalı olmayan bir sıralama algoritmasıdır.
  • Anahtarlar basamaklara ayrılır: tamsayıda rakamlar, dizgide karakterler.
  • Her geçişte, aynı konumda aynı değeri taşıyan öğeler aynı kovaya (bucket) konur.
  • Her basamak için ayrı bir geçiş yapılır; geçişin kendisi kararlı (stable) bir sayarak sıralamadır (counting sort).
LSD (Least Significant Digit)En az anlamlı basamaktan (en sağdaki) en anlamlıya doğru. En uzun dizginin uzunluğu W kadar geçiş; kısa dizgiler boş karakterle tamamlanır.
MSD (Most Significant Digit)En soldaki karakterden başlar, her kovayı ayrı ayrı özyinelemeli sıralar. Değişken uzunluklu dizgilere uygundur.
Neden sağdan? Son geçiş en anlamlı basamağa göre yapılır; kararlılık sayesinde bu basamakta eşit olan öğeler önceki geçişlerin kurduğu (daha az anlamlı basamaklara göre) sırayı korur.

Dizgi Sıralama · Adım adım

LSD Radix Sıralama: Sayısal Örnek

Veri kümesi: [170, 45, 75, 90, 802, 24, 2, 66]. Kısa sayılar soldan 0 ile tamamlanmış gibi düşünülür (soluk rakamlar).

öncesonra170045075090802024002066170090802002024045075066

1. geçiş (birler basamağı): anahtarlar (0, 5, 5, 0, 2, 4, 2, 6) → [170, 90, 802, 2, 24, 45, 75, 66]. Eşit anahtarlar (170, 90) giriş sırasını korur.

öncesonra170090802002024045075066802002024045066170075090

2. geçiş (onlar basamağı): anahtarlar (7, 9, 0, 0, 2, 4, 7, 6) → [802, 2, 24, 45, 66, 170, 75, 90].

öncesonra802002024045066170075090002024045066075090170802

3. geçiş (yüzler basamağı): anahtarlar (8, 0, 0, 0, 0, 1, 0, 0) → [2, 24, 45, 66, 75, 90, 170, 802]. Dizi sıralandı.

Dizgi Sıralama

LSD Radix: Kararlılık Neden Gerekli?

girdi456167276467273123birler273123456276167467onlar123456167467273276yüzler123167273276456467
  • Yeşil sütunlar, o ana kadar sıralı hâle gelen son eklerdir: k geçişten sonra dizi, son k basamağa göre sıralıdır.
  • 2. geçişte 167 ile 467'nin onlar basamağı eşittir (6); 1. geçişten gelen sıra (7 = 7, giriş sırası) korunur.
  • Alt sıralama kararsız olsaydı, örneğin 273 ile 276 son geçişte yer değiştirebilir ve sonuç bozulurdu.

Dizgi Sıralama · Adım adım

LSD Radix Sıralama: Dizgiler

Simülatördeki örnek: cab, dab, bad, dad, fad, ace, bee, bed, add, ebb (W = 3, sağdan sola 3 geçiş).

öncecabdabbaddadfadacebeebedaddebbsonracabdabebbbaddadfadbedaddacebeekovalarb: cab dab ebbd: bad dad fad bed adde: ace bee

1. geçiş (3. karakter): son karaktere göre kovalara dağıtılır; aynı kovadakiler (cab, dab) giriş sırasını korur.

öncecabdabebbbaddadfadbedaddacebeesonracabdabbaddadfadebbaceaddbedbeekovalara: cab dab bad dad fadb: ebbc: aced: adde: bed bee

2. geçiş (2. karakter): ortanca karaktere göre; 'a' kovasında cab, dab, bad, dad, fad önceki sırayla (b < d) kalır.

öncecabdabbaddadfadebbaceaddbedbeesonraaceaddbadbedbeecabdabdadebbfadkovalara: ace addb: bad bed beec: cabd: dab dade: ebbf: fad

3. geçiş (1. karakter): ilk karaktere göre; artık dizi sözlüksel olarak sıralıdır: ace, add, bad, bed, bee, cab, dab, dad, ebb, fad.

Dizgi Sıralama

LSD Radix Sıralama: Java Kodu

void radixSirala(String[] a) {
  int W = enUzun(a);               // en uzun dizgi
  for (int d = W - 1; d >= 0; d--)
    sayarakSirala(a, d);           // sağdan sola
}
void sayarakSirala(String[] a, int d) {
  int[] say = new int[256];        // ASCII
  for (String s : a) say[kar(s, d)]++;
  for (int r = 1; r < 256; r++) say[r] += say[r - 1];
  String[] gec = new String[a.length];
  for (int i = a.length - 1; i >= 0; i--)   // kararlı
    gec[--say[kar(a[i], d)]] = a[i];
  System.arraycopy(gec, 0, a, 0, a.length);
}
int kar(String s, int d) {         // kısa dizgi → 0
  return d < s.length() ? s.charAt(d) : 0;
}
  • Sayma: d. karakteri c olan dizgi sayısı say[c].
  • Önek toplamı: say[c] artık c kovasının bittiği konumu gösterir.
  • Yerleştirme sondan başa yapılır; böylece eşit anahtarlar aynı sırada kalır (kararlılık).
  • Uzunluğu yetmeyen dizgi için kar 0 döndürür: "car", "cart"tan önce gelir.

Bir geçiş O(N + R), R = 256 alfabe boyutu; W geçiş → O(W · (N + R)).

Dizgi Sıralama

MSD Radix Sıralama: Soldan Sağa

BADGE\0BANNER\0COFFEE\0COMPARISON\0COMPUTER\0MIDNIGHT\0WANDER\0WARDROBE\0WORKER\0
  1. Tüm dizgiler ilk karaktere göre kovalara ayrılır (B, C, M, W).
  2. Her kova, bir sonraki karaktere göre ayrı ayrı, özyinelemeli sıralanır.
  3. Tek elemanlı kovada ya da dizgi sonunda (\0) durulur.
Yeşil hücreler, kelimenin yerini belirlemek için okunması gereken karakterlerdir (ayırt edici önek). MSD yalnızca bunları inceler: MIDNIGHT için tek karakter yeter, COMPARISON / COMPUTER için beş.

Uzun ortak önekli dizgilerde MSD de tüm karakterleri okur. Küçük kovalarda R = 256 boyutlu sayma dizisi pahalı olduğundan pratikte küçük alt dizilere eklemeli sıralama uygulanır.

Dizgi Sıralama

Zaman Karmaşıklığı ve Karşılaştırma

  • LSD: W geçiş (W: en uzun dizginin uzunluğu), her geçiş N dizgi + R kova → O(W · (N + R)).
  • Alfabe sabitse (R = 256) maliyet O(W · N) olur: en uzun dizginin uzunluğu × eleman sayısı.
YöntemZamanEk bellekKararlı
Yer değiştirmeli sıralama + compareToO(N² · W)O(1)hayır
Birleştirme sıralaması + compareToO(W · N log N)O(N)evet
LSD radixO(W · (N + R))O(N + R)evet
MSD radixO(N · W) en kötüO(N + W · R)evet
Ne zaman radix? Anahtarlar kısa ve sabit uzunlukluysa (plaka, posta kodu, IP adresi, 3 harfli kodlar) LSD idealdir. Uzunluklar çok farklıysa MSD ya da karşılaştırmalı sıralama tercih edilir.

Düzenli İfadeler

Düzenli İfadeler (Regular Expressions)

  • Düzenli ifade (regular expression, regex): bir arama örüntüsünü tanımlayan karakter dizisidir.
  • Metinde örüntüye uyan tüm parçaları bulmak, doğrulamak, ayıklamak ya da değiştirmek için kullanılır.
  • Metin işleme işlerini otomatikleştirir: günlük (log) analizi, form doğrulama, veri temizleme, derleyicilerde sözcük çözümleme (lexer).
  • Kuramsal temeli: her düzenli ifadeye eşdeğer bir sonlu durum makinesi vardır (Kleene teoremi).
ÖrüntüMetinEşleşmeler
colou?rcolor colourcolor, colour
gr(a|e)ygray grey groygray, grey
\d+20.99 TL, 5 adet20, 99, 5
\bkod\bkod kodlamayalnızca "kod"
Java'da: java.util.regex (Pattern, Matcher) ve String.matches, replaceAll, split. Java dizgisinde ters bölü iki kez yazılır: "\\d+".

Düzenli İfadeler

Temel Operatörler ve Kavramlar

Op.AnlamıÖrnekİçinde bulunurBulunmaz
.Herhangi bir tek karakter (yeni satır hariç)a.cabc, a7cac
*Önceki öğenin 0 ya da daha fazla tekrarıab*cac, abbcadc
+Önceki öğenin 1 ya da daha fazla tekrarıab+cabc, abbcac
?Önceki öğenin 0 ya da 1 kez geçmesiab?cac, abcabbc
[ ]Kümedeki karakterlerden biri[ck]arcar, karbar
^Dizginin başı^ababccab
$Dizginin sonuab$cababc
( )Gruplama; alt ifade tanımlar^(ab)+$ab, abababa

Sütunlar, dizginin içinde örüntüye uyan bir parça bulunup bulunmadığını gösterir (Matcher.find). *, +, ? yalnızca hemen önlerindeki öğeye (karakter, küme ya da grup) uygulanır.

Düzenli İfadeler

Karmaşık Operatörler ve Özel Karakterler

İfadeAnlamı
atek bir 'a' karakteri
abctam olarak "abc"
{ }belirli sayıda tekrar: \d{4}
|seçenekler: kedi|köpek
\bkelime sınırı (başı ya da sonu)
\dbir rakam: [0-9]
\wbir kelime karakteri: [a-zA-Z0-9_]
\sboşluk karakteri: boşluk, tab, yeni satır
  • Büyük harfli biçimler tümleyendir: \D rakam olmayan, \W kelime karakteri olmayan, \S boşluk olmayan karakter.
  • Özel karakterin kendisi için kaçış gerekir: \. nokta, \+ artı, \( parantez.
  • \w tek bir karakterle eşleşir; bir kelime için \w+ yazılır.
Java'da \w varsayılan olarak yalnızca ASCII harfleri kapsar: "şeker" içindeki 'ş' eşleşmez. Türkçe için \p{L} ya da Pattern.UNICODE_CHARACTER_CLASS kullanılır.

Düzenli İfadeler

Karakter Sınıfları

Karakter sınıfları
[abc]'a', 'b' ya da 'c'
[a-z]herhangi bir küçük harf
[A-Z]herhangi bir büyük harf
[0-9]herhangi bir rakam
[a-zA-Z_]harf ya da alt çizgi
Tümleyen karakter sınıfları
[^abc]'a', 'b', 'c' dışındaki karakter
[^0-9]rakam olmayan karakter
[^0-9]+"ab12cd" → "ab", "cd"
  • ^ köşeli parantezin içinde ve başında "değil" anlamına gelir; dışarıda dizginin başıdır.
  • Küme içinde ., *, + özel değildir: [.+] nokta ya da artı ile eşleşir. Tire (-) aralık bildirir; kendisi için başa ya da sona yazılır.
  • [a-z] aralığı karakter kodlarına dayanır; ç, ğ, ı, ö, ş, ü bu aralıkta değildir.

Düzenli İfadeler

Yinelenen Karakterler ve Gruplama

Niceleyiciler (quantifiers)

a*sıfır ya da daha fazla 'a'
a+bir ya da daha fazla 'a'
a?sıfır ya da bir 'a'
a{3}tam olarak üç 'a'
a{2,4}iki ile dört arası 'a'
a{2,}en az iki 'a'

Gruplama

(abc)tam olarak "abc"; grup olarak yakalanır
(a|b|c)'a', 'b' ya da 'c'; grup olarak yakalanır
(ab)+"ab", "abab", …

Yakalanan grup Java'da m.group(1) ile okunur.

Açgözlü ve tembel: a{2,4}, "aaaaa" içinde mümkün olan en uzun parçayı (aaaa) alır. Niceleyiciden sonra ? yazılırsa en kısa eşleşme seçilir: "<.+?>", "<b>x</b>" içinde yalnızca "<b>" ile eşleşir.

Düzenli İfadeler

İleri ve Geri Bakış (Lookahead, Lookbehind)

ÖrüntüAdıEşleşme koşulu"ab ac ba"
a(?=b)ileri bakış (lookahead)'a', ardından 'b' geliyorsaab ac ba
a(?!b)olumsuz ileri bakış'a', ardından 'b' gelmiyorsaab ac ba
(?<=b)ageri bakış (lookbehind)'a', önünde 'b' varsaab ac ba
(?<!b)aolumsuz geri bakış'a', önünde 'b' yoksaab ac ba
  • Bakış ifadeleri bir konumu sınar, karakter tüketmez: a(?=b) eşleşmesi yalnızca "a"dır, 'b' eşleşmeye dahil olmaz.
  • Örnek: ^(?=.*\d)(?=.*[A-Z]).{8,}$ en az bir rakam ve bir büyük harf içeren, en az 8 karakterlik parolayı doğrular.

Düzenli İfadeler

Örnek: Doğrulama İfadeleri

AmaçDüzenli ifade
E-posta^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Telefon^(\+\d{1,3}[- ]?)?\d{10}$
URL^https?:\/\/[^\s/$.?#].[^\s]*$
E-posta[…]+ kullanıcı adı, @, alan adı, \. gerçek nokta, en az 2 harfli uzantı. ✓ ali.veli@giresun.edu.tr ✗ ali@tr ✗ a b@x.com
Telefonİsteğe bağlı (…)? ülke kodu: + ve 1–3 rakam, ardından tire ya da boşluk; sonra tam 10 rakam. ✓ +90 5321234567 ✓ 5321234567 ✗ 0532 123 45 67
URLs? http ya da https; ilk karakter boşluk, /, $, ., ?, # olamaz; sonra boşluksuz karakterler. ✓ https://giresun.edu.tr ✗ ftp://x.com ✗ "http:// x"

Bu ifadeler pratik yaklaşımlardır; standartların (RFC 5322 e-posta, RFC 3986 URI) tamamını kapsamaz.

Düzenli İfadeler

Ayrıştırma Ağacı: URL Örneği

url'http://'sunucu':'port'/'kelime'.'sunucu'4949''didit'kelime'.'sunucu'csail'kelime'.'kelime'mit''edu'

http://didit.csail.mit.edu:4949/ için dilbilgisi (grammar):

url    ::= 'http://' sunucu
           ':' port '/'
sunucu ::= kelime '.' sunucu
         | kelime
kelime ::= [a-z]+
port   ::= [0-9]+
Bu dilbilgisi özyinelemeli görünse de kuyruk özyinelemesidir; eşdeğer düzenli ifade: http://([a-z]+\.)*[a-z]+:[0-9]+/. Dengeli parantez gibi iç içe yapılar ise düzenli ifadeyle tanımlanamaz; bağlamdan bağımsız dilbilgisi ve ayrıştırıcı (parser) gerekir.

Düzenli İfadeler

Java'da Düzenli İfadeler: Pattern ve Matcher

String girdi = "Ad: Ali Veli, Yaş: 30, E-posta: ali.veli@ornek.com";
Pattern p = Pattern.compile("Yaş: (\\d+),");  // derle
Matcher m = p.matcher(girdi);
if (m.find()) {                          // ilk eşleşmeyi bul
  int yas = Integer.parseInt(m.group(1)); // 1. grup: "30"
  System.out.println("Yaş: " + yas);
}
Örüntügroup(1)Açıklama
Ad: (.*?),Ali Velitembel .*?: ilk virgülde durur
Yaş: (\d+),30bir ya da daha çok rakam
E-posta: (.*?)$ali.veli@ornek.comsatır sonuna kadar
  • Aynı iş düzenli ifade kullanmadan, indexOf ve substring ile de yapılabilir: başlangıç işareti (ör. "Yaş: ") bulunur, bitiş işaretine (",") kadar kesilir.
  • find() metnin bir parçasını, matches() tamamını eşleştirmeye çalışır.

Düzenli İfadeler

Deneyin: Düzenli İfade Sınayıcı

Tarayıcının JavaScript düzenli ifade motoru kullanılır; söz dizimi Java ile büyük ölçüde aynıdır. Eşleşmeler vurgulanır, gruplar listelenir.

Sonlu Durum Makineleri

Sonlu Durum Makineleri (Finite State Machines)

  • Sonlu durum makinesi (finite state machine, FSM): bir dizgiyi karakter karakter işleyen matematiksel model.
  • Sonlu sayıda durumu vardır; bellek yalnızca şu anki durumdur.
  • Basit ve anlaşılması kolaydır, yine de karmaşık dizgi analizi problemlerini (sözcük çözümleme, protokol, örüntü arama) ele alabilir.
Biçimsel tanım: M = (Q, Σ, δ, q₀, F)
Durumlar Q (states)Makinenin bulunabileceği farklı durumlar.
Alfabe Σ (alphabet)Kabul edilen girdi sembollerinin kümesi.
Başlangıç durumu q₀İşlemenin başladığı durum.
Geçişler δ (transitions)δ(durum, sembol) → yeni durum.
Kabul durumları F ⊆ QDizgi bittiğinde makine bunlardan birindeyse dizgi kabul edilir.

Sonlu Durum Makineleri

FSM Türleri: DFA, NFA, ε-NFA

DFADeterministik sonlu otomat (Deterministic Finite Automaton): her (durum, sembol) çifti için tam olarak bir geçiş vardır. Çalıştırması basittir: O(n).
NFADeterministik olmayan sonlu otomat: bir (durum, sembol) çifti için sıfır, bir ya da birden fazla geçiş tanımlanabilir. Makine aynı anda bir durum kümesinde bulunur.
ε-NFASembol okumadan yapılan boş geçişlere (epsilon, ε) izin veren NFA. Düzenli ifadeden doğrudan kurulur (Thompson yapısı).
Düzenli ifadeε-NFANFADFAThompsonε-kapanışalt küme
  • Üçü de aynı dilleri (düzenli diller) tanır: her NFA, alt küme kurulumu (subset construction) ile bir DFA'ya çevrilir; ancak durum sayısı en kötü 2ⁿ'e çıkabilir.
  • grep, lex/flex ve derleyici sözcük çözümleyicileri bu zinciri kullanır.

Sonlu Durum Makineleri

Kullanımı: DFA Simülasyonu

  1. Başlangıç durumuna geç.
  2. Her karakter için durumu geçiş tablosundan güncelle.
  3. Dizgi bitince son durumun kabul durumu olup olmadığını denetle.
boolean kabulEder(int[][] gecis, boolean[] kabul,
                  String s) {
  int durum = 0;                     // başlangıç durumu
  for (char c : s.toCharArray())
    durum = gecis[durum][c - '0'];   // tek geçiş
  return kabul[durum];               // son durum kabul mü?
}
Geçiş tablosu int[|Q|][|Σ|] boyutundadır. Her karakter için bir tablo okuması yapılır: n uzunluklu dizgi O(n) zamanda, geri dönmeden (backtracking olmadan) işlenir.

Sonlu Durum Makineleri

Örnek: "nice" Kelimesini Tanıyan Makine

nice≠n≠i≠c≠e1Başla2n_bulundu3i_bulundu4c_bulundu6Hata7Başarı
  • "nice" kelimesini tanıyan makine: her durum, şimdiye kadar okunan öneki temsil eder (ε, n, ni, nic, nice).
  • Beklenen karakter gelmezse (≠n, ≠i, …) Hata durumuna gidilir ve orada kalınır (tuzak durum, trap state).
  • "nice" → 1 → 2 → 3 → 4 → 7: kabul. "nine" → 1 → 2 → 3 → 6: ret (üçüncü karakter 'n' ≠ 'c').

Sonlu Durum Makineleri · Adım adım

Örnek: İkili Alfabe Üzerinde DFA

011111010000AEFDCB

Başlangıç: durum A. Girdi: 10011.

011111010000AEFDCB

1. sembol 1: δ(A, 1) = B.

011111010000AEFDCB

2. sembol 0: δ(B, 0) = B.

011111010000AEFDCB

3. sembol 0: δ(B, 0) = B.

011111010000AEFDCB

4. sembol 1: δ(B, 1) = C.

011111010000AEFDCB

5. sembol 1: δ(C, 1) = D. Girdi bitti; D kabul durumu → kabul.

δ01
→ AEB
BBC
CBD
D *DA
EEF
FFA

→ başlangıç, * kabul. Her hücrede tek durum: DFA.

Sonlu Durum Makineleri

Örnek: "ACACAGA" Örüntüsünü Arayan Otomat

ACACAGAAAAACC01234567
metinGACACACAGA
durum0123454567
  • Durum q = metnin sonunda örüntüyle uyuşan en uzun önekin uzunluğu. Çizilmeyen tüm geçişler 0'a gider. Durum 7'ye ulaşınca eşleşme bulunur (burada konum 3'te).
  • 7. karakter 'C' gelince 5 → 4 dönülür: "ACACAC"nin sonu "ACAC" öneki gibi devam edebilir. Bu, KMP'deki önek fonksiyonunun otomat biçimidir: ön işlem O(m · |Σ|), arama O(n).

Sonlu Durum Makineleri · Kodu adım adım çalıştır

FSM ile Sayı Ayrıştırma: Kodu İzle

$20.99 ve 5.BASLARAKAMONDALIK

Girdi "$20.99 ve 5.". Durum BASLA, tampon boş.

$20.99 ve 5.BASLARAKAMONDALIK

'$' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.

$20.99 ve 5.BASLARAKAMONDALIK

'2' rakam ve durum BASLA → RAKAM; tampona eklendi.

$20.99 ve 5.BASLARAKAMONDALIK

'0' rakam: durum RAKAM kalır, tampona eklenir.

$20.99 ve 5.BASLARAKAMONDALIK

'.' geldi → ONDALIK durumuna geçildi, nokta tampona eklendi.

$20.99 ve 5.BASLARAKAMONDALIK

'9' rakam: durum ONDALIK kalır, tampona eklenir.

$20.99 ve 5.BASLARAKAMONDALIK

'9' rakam: durum ONDALIK kalır, tampona eklenir.

$20.99 ve 5.BASLARAKAMONDALIK

' ' sayı karakteri değil: sayı bitti, 20.99 yazdırıldı; BASLA'ya dönülür.

$20.99 ve 5.BASLARAKAMONDALIK

'v' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.

$20.99 ve 5.BASLARAKAMONDALIK

'e' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.

$20.99 ve 5.BASLARAKAMONDALIK

' ' ne rakam ne nokta; durum BASLA, hiçbir şey yapılmaz.

$20.99 ve 5.BASLARAKAMONDALIK

'5' rakam ve durum BASLA → RAKAM; tampona eklendi.

$20.99 ve 5.BASLARAKAMONDALIK

'.' geldi → ONDALIK durumuna geçildi, nokta tampona eklendi.

$20.99 ve 5.BASLARAKAMONDALIK

Girdi bitti; durum ONDALIK olduğundan tampon yazdırılır: 5.. Sondaki nokta da sayıya katıldı (kusur; bkz. Alıştırmalar).

void sayilariBul(String s) {
  Durum d = Durum.BASLA;
  StringBuilder tampon = new StringBuilder();
  for (char c : s.toCharArray()) {
    boolean rakam = Character.isDigit(c);
    if (rakam) {
      if (d == Durum.BASLA) d = Durum.RAKAM;
      tampon.append(c);
    } else if (c == '.' && d != Durum.ONDALIK) {
      d = Durum.ONDALIK;
      tampon.append(c);
    } else if (d != Durum.BASLA) {  // sayı bitti
      System.out.println(tampon);
      tampon.setLength(0);
      d = Durum.BASLA;
    }
  }
  if (d != Durum.BASLA) System.out.println(tampon);
}

Düzenleme Mesafesi

Levenshtein Mesafesi (Edit Distance)

  • Levenshtein mesafesi (V. Levenshtein, 1965): iki dizgi arasındaki farkı nicel olarak ölçen bir metriktir.
  • Bir dizgiyi diğerine dönüştürmek için gereken en az tek karakterlik düzenleme sayısıdır.
  • Otomatik düzeltme ve tahmin sistemlerinde, yazım denetiminde, DNA dizilerini karşılaştırmada, bulanık (fuzzy) aramada kullanılır.
  • Metrik özellikleri: d(a, a) = 0, d(a, b) = d(b, a), üçgen eşitsizliği.
Ekleme (insertion)Bir karakter eklemek: "sittin" → "sitting"
Silme (deletion)Bir karakteri çıkarmak: "shine" → "shin"
Değiştirme (substitution)Bir karakteri başkasıyla değiştirmek: "kitten" → "sitten"
kitten → sitten (k→s) → sittin (e→i) → sitting (+g): d = 3. Daha kısa bir yol yoktur; bunu dinamik programlama kanıtlar.

Düzenleme Mesafesi

Düzenleme Örnekleri

HONDAHHOYUNNDDAAIHYUNDAI

HONDA → HYUNDAI: O→Y değiştir, U ekle, I ekle: d = 3

rainsainshinshineshinerhineraineraineshinetshinetrhinetrainetraine(a) 3(b) 3(c) 4

değiştirme ekleme silme

  • (a) rain → sain → shin → shine · (b) shine → rhine → raine → rain (e silinir) · (c) shine → tshine → trhine → traine → train (e silinir). Üstü çizili turuncu harf silinir.
  • Mesafe simetriktir: (a) ile (b) birbirinin tersidir; ekleme ↔ silme yer değiştirir.

Düzenleme Mesafesi

Levenshtein Mesafesini Hesaplama

D[i][j] = a'nın ilk i karakterini b'nin ilk j karakterine dönüştürmenin en az maliyeti.

D[i][0] = i (i silme) · D[0][j] = j (j ekleme)
ai = bj ise D[i][j] = D[i−1][j−1]
aksi hâlde D[i][j] = 1 + min( D[i−1][j] silme, D[i][j−1] ekleme, D[i−1][j−1] değiştirme )
  • Dinamik programlama: her alt problem bir kez çözülür, (m+1) × (n+1) tabloda saklanır; cevap sağ alt köşededir.
  • Bir hücre yalnızca üst, sol ve sol üst komşulara bağlıdır → tablo satır satır doldurulur.
  • Zaman O(m · n); bellek O(m · n), yalnızca mesafe gerekiyorsa iki satırla O(min(m, n)).

Düzenleme Mesafesi · Adım adım

DP Tablosu: CARS → PAIRS

a = CARS (satırlar), b = PAIRS (sütunlar)

εPAIRS
ε012345
C1
A2
R3
S4

Başlangıç: ilk satır 0..5 (ε → P, PA, … : ekleme), ilk sütun 0..4 (C, CA, … → ε : silme).

εPAIRS
ε012345
C112345
A2
R3
S4

1. satır (C) dolduruldu. C ≠ P: D[1][1] = 1 + min(0, 1, 1) = 1 (değiştirme).

εPAIRS
ε012345
C112345
A221234
R3
S4

2. satır (A) dolduruldu. A = A: D[2][2] = D[1][1] = 1, maliyet eklenmez.

εPAIRS
ε012345
C112345
A221234
R332223
S4

3. satır (R) dolduruldu. R = R: D[3][4] = D[2][3] = 2. A ≠ I: D[2][3] = 1 + min(1, 2, 3) = 2.

εPAIRS
ε012345
C112345
A221234
R332223
S443332

4. satır (S) dolduruldu. S = S: D[4][5] = D[3][4] = 2.

εPAIRS
ε012345
C112345
A221234
R332223
S443332

Sonuç D[4][5] = 2. Geri izleme: C→P değiştir, A eşit, I ekle, R ve S eşit: CARS → PARS → PAIRS.

Düzenleme Mesafesi

Levenshtein: Java Kodu

int levenshtein(String a, String b) {
  int m = a.length(), n = b.length();
  int[][] D = new int[m + 1][n + 1];
  for (int i = 0; i <= m; i++) D[i][0] = i;  // silme
  for (int j = 0; j <= n; j++) D[0][j] = j;  // ekleme
  for (int i = 1; i <= m; i++)
    for (int j = 1; j <= n; j++)
      if (a.charAt(i - 1) == b.charAt(j - 1))
        D[i][j] = D[i - 1][j - 1];            // eşit
      else
        D[i][j] = 1 + Math.min(D[i - 1][j - 1], // değiştir
                  Math.min(D[i][j - 1],         // ekle
                           D[i - 1][j]));       // sil
  return D[m][n];
}
  • Tablo indisi i, dizgi indisi i − 1'dir: D'nin 0. satırı boş önek içindir.
  • Örnekler: kitten → sitting = 3, ercan → sercan = 1, apple → banana = 5.

En Uzun Ortak Alt Dizi

En Uzun Ortak Alt Dizi (LCS)

  • En uzun ortak alt dizi (longest common subsequence, LCS): iki dizginin her ikisinde de sıralı olarak bulunan en uzun dizi.
  • Karakterlerin ardışık olması gerekmez, ancak göreli sıraları korunmalıdır.
  • İki dizgi arasındaki benzerlik seviyesini ölçer: diff, sürüm kontrolü, DNA hizalama, intihal tespiti.
Dizi 1Dizi 2AGGTABGXTXAYB

LCS = GTAB, uzunluk 4

dizi 1dizi 2acbaedabcadf

LCS = acad, uzunluk 4 (abad da olur)

Alt dizi ≠ alt dizgi: "GTAB", GXTXAYB'nin alt dizisidir ama alt dizgisi (substring) değildir. LCS tek olmak zorunda değildir; uzunluğu tektir.

En Uzun Ortak Alt Dizi

Dinamik Programlama Yaklaşımı

String lcs(String a, String b) {
  int m = a.length(), n = b.length();
  int[][] L = new int[m + 1][n + 1];
  for (int i = 1; i <= m; i++)
    for (int j = 1; j <= n; j++)
      if (a.charAt(i - 1) == b.charAt(j - 1))
        L[i][j] = L[i - 1][j - 1] + 1;
      else
        L[i][j] = Math.max(L[i - 1][j], L[i][j - 1]);
  StringBuilder s = new StringBuilder(); // geri izle
  for (int i = m, j = n; i > 0 && j > 0; )
    if (a.charAt(i - 1) == b.charAt(j - 1)) {
      s.insert(0, a.charAt(i - 1)); i--; j--;
    } else if (L[i - 1][j] > L[i][j - 1]) i--;
    else j--;
  return s.toString();
}
  1. Uzunluklar m ve n; (m+1) × (n+1) tablo.
  2. İlk satır ve sütun 0.
  3. A[i] = B[j] ise hücre = sol üst + 1.
  4. A[i] ≠ B[j] ise hücre = max(üst, sol).
  5. Son hücre LCS uzunluğudur; dizinin kendisi geri izlemeyle bulunur.

Zaman ve bellek O(m · n); geri izleme O(m + n).

En Uzun Ortak Alt Dizi · Adım adım

LCS Tablosu: AGGTAB · GXTXAYB

A = AGGTAB (satırlar), B = GXTXAYB (sütunlar)

εGXTXAYB
ε00000000
A0
G0
G0
T0
A0
B0

İlk satır ve sütun 0: boş dizginin herhangi bir dizgiyle LCS'si boştur.

εGXTXAYB
ε00000000
A00000111
G0
G0
T0
A0
B0

1. satır (A). A yalnızca B[5] = A ile eşleşir: L[1][5] = 0 + 1 = 1; sağa doğru max ile 1 taşınır.

εGXTXAYB
ε00000000
A00000111
G01111111
G0
T0
A0
B0

2. satır (G). G = G (j = 1): L[2][1] = 1. Satırın geri kalanı max(üst, sol) = 1.

εGXTXAYB
ε00000000
A00000111
G01111111
G01111111
T0
A0
B0

3. satır (G). İkinci G de yalnızca 1 verir: aynı G iki kez kullanılamaz (sol üst = 0).

εGXTXAYB
ε00000000
A00000111
G01111111
G01111111
T01122222
A0
B0

4. satır (T). T = T (j = 3): L[4][3] = L[3][2] + 1 = 2 → "GT".

εGXTXAYB
ε00000000
A00000111
G01111111
G01111111
T01122222
A01122333
B0

5. satır (A). A = A (j = 5): L[5][5] = L[4][4] + 1 = 3 → "GTA".

εGXTXAYB
ε00000000
A00000111
G01111111
G01111111
T01122222
A01122333
B01122334

6. satır (B). B = B (j = 7): L[6][7] = L[5][6] + 1 = 4 → "GTAB".

εGXTXAYB
ε00000000
A00000111
G01111111
G01111111
T01122222
A01122333
B01122334

Geri izleme sağ alttan: eşleşmede çapraz (turuncu, karakter LCS'ye eklenir), değilse büyük olan komşuya. Sonuç GTAB, uzunluk 4.

En Uzun Ortak Alt Dizi

Örnek: DNA Dizilerinde LCS

ACCGGTGGACAATTCAGGAAAGAGATATGCAC
  • Eşleşen karakterleri birleştiren çizgiler kesişmez: göreli sıra korunur. Bu kural sağlanan her eşleme bir ortak alt dizidir.
  • DP sonucu: LCS = GGAAATTCA, uzunluk 9.
Dikkat: Göz kararı eşleme yanıltıcıdır. Örneğin AAAATTCA (8 karakter) da geçerli bir ortak alt dizidir, ama en uzun değildir; doğru cevabı DP tablosu verir.

En Uzun Ortak Alt Dizi

Benzerlik Ölçülerinin Karşılaştırılması

ÖlçüNe ölçer?ZamanAGGTAB · GXTXAYB
Hammingeşit uzunlukta, farklı konum sayısıO(n)tanımsız (6 ≠ 7)
Levenshteinekle / sil / değiştir sayısıO(m · n)4
LCSen uzun ortak alt diziO(m · n)4 (GTAB)
En uzun ortak alt dizgiardışık ortak parçaO(m · n)1 (ör. "G")
  • Yalnızca ekleme ve silmeye izin verilirse mesafe = m + n − 2 · LCS: 6 + 7 − 8 = 5; değiştirmeye de izin veren Levenshtein bunu 4'e indirir.
  • En uzun ortak alt dizgi: eşleşmede L[i][j] = L[i−1][j−1] + 1, eşleşmezse 0; cevap tablonun en büyük değeridir (ercan · sercan → "ercan").
  • Benzerlik oranı örneği: 1 − d / max(m, n). kitten · sitting: 1 − 3/7 ≈ 0,57.

Dizgi Dönüşümleri

Sonek Dizisi (Suffix Array)

  • Sonek dizisi (suffix array): bir dizginin tüm soneklerinin alfabetik sıraya dizilmiş hâlinin başlangıç indisleri.
  • Her sonek, dizginin belirli bir konumundan başlayıp sonuna kadar giden alt dizgidir. Sonek dizisi tüm alt dizgilerin sıkı bir temsilidir: her alt dizgi bir sonekin önekidir.
isonek
0banana
1anana
2nana
3ana
4na
5a
sıraSAsıralı sonek
05a
13ana
21anana
30banana
44na
52nana

"banana" → SA = [5, 3, 1, 0, 4, 2]. Kullanım: dizgi arama, sıralama, genetik dizilim analizi, BWT ve veri sıkıştırma.

Dizgi Dönüşümleri

Sonek Dizisi Oluşturma Yöntemleri

YöntemFikirZaman
Kaba kuvvetTüm sonekleri oluştur, Arrays.sort ile sırala; her karşılaştırma O(n)O(n² log n)
Manber–Myers (1990)Önek ikiye katlama: k karakterlik sıralardan 2k karakterlik sırayı harf karşılaştırmadan, sıra çiftleriyle radix sıralayarak bulurO(n log n)
Larsson–Sadakane (1999)Aynı ikiye katlama; yalnızca henüz ayrışmamış gruplar, art arda soneklerin sıraları karşılaştırılarak yeniden sıralanırO(n log n)
DC3 (2003), SA-IS (2009)Soneklerin bir kısmını özyinelemeli sıralayıp kalanı birleştirirO(n)
Önek ikiye katlama yöntemleri O(n log n) zamanlıdır, doğrusal değildir. Doğrusal zamanlı kurulum DC3 ve SA-IS gibi sonraki algoritmalarla mümkündür.

Dizgi Dönüşümleri · Adım adım

Önek İkiye Katlama (Prefix Doubling)

Manber–Myers fikri, "banana" üzerinde: k karakterlik sıralardan 2k karakterlik sıra elde edilir. log₂ n tur, her tur radix ile O(n).

iilk 1 karakteranahtaryeni sıra
1a'a'0
3a'a'0
5a'a'0
0b'b'1
2n'n'2
4n'n'2

k = 1: sonekler ilk karakterlerine göre sıralanır: a → 0, b → 1, n → 2. Eşit sıralar henüz ayrışmamıştır.

iilk 2 karakteranahtaryeni sıra
5a(0, −1)0
1an(0, 2)1
3an(0, 2)1
0ba(1, 0)2
2na(2, 0)3
4na(2, 0)3

k = 2: anahtar = (sıra[i], sıra[i + 1]); i + 1 ≥ n ise −1. Harf karşılaştırılmaz, yalnızca sayı çiftleri sıralanır.

iilk 4 karakteranahtaryeni sıra
5a(0, −1)0
3ana(1, 0)1
1anan(1, 1)2
0bana(2, 3)3
4na(3, −1)4
2nana(3, 3)5

k = 4: anahtar = (sıra[i], sıra[i + 2]); i + 2 ≥ n ise −1. Harf karşılaştırılmaz, yalnızca sayı çiftleri sıralanır. Tüm sıralar farklı → SA = [5, 3, 1, 0, 4, 2].

Dizgi Dönüşümleri

Sonek Dizisiyle Arama

  • Sonekler sıralı olduğundan, P örüntüsüyle başlayan sonekler SA'da bitişik bir aralık oluşturur.
  • Aralığın iki ucu ikili arama ile bulunur: O(log n) adım × O(m) karşılaştırma = O(m log n).
  • Sonek trie'sine göre çok az bellek: yalnızca n tamsayı.
  • LCP dizisi (komşu soneklerin en uzun ortak öneki) eklenirse en uzun tekrar eden alt dizgi O(n)'de bulunur.
sıraSAsonek
05a
13ana
21anana
30banana
44na
52nana
Örnek: "banana" içinde P = "an". Orta = sıra 2 ("anana") "an" ile başlar; sol ve sağ sınır aramaları aralığı [1, 2] bulur → "an", 3 ve 1 konumlarında geçer.

Dizgi Dönüşümleri

Burrows–Wheeler Dönüşümü (BWT)

  • Burrows–Wheeler dönüşümü (BWT, 1994): girdiyi yeniden düzenler; karakterleri değiştirmez, yalnızca yerlerini değiştirir.
  • Aynı karakterlerin bir araya toplanmasını sağlar: benzer bağlamdan önce gelen karakterler yan yana düşer.
  • Sıkıştırma algoritmalarının performansını artırır.
  • Tersine çevrilebilir: orijinal veri dönüşümden geri elde edilir.

Uygulama adımları

  1. Girdi dizgisinin tüm döndürülmüş hâllerini (cyclic rotations) oluştur.
  2. Döndürmeleri alfabetik olarak sırala.
  3. Sıralı döndürmelerin son karakterlerinden yeni bir dizgi oluştur (L sütunu).
  4. Orijinal dizginin sıralı listedeki satır numarasını sakla (ya da sona tekil bir $ ekle).
bzip2 zinciri: BWT → Move-to-Front (tekrarlar küçük sayılara dönüşür) → Run-Length Encoding → Huffman kodlama.

Dizgi Dönüşümleri · Adım adım

BWT Örneği: BANANA

Girdi: BANANA

döndürmelerBANANAANANABNANABAANABANNABANAABANAN012345

1. Tüm döndürmeler: BANANA, ANANAB, NANABA, ANABAN, NABANA, ABANAN (ilk karakter sona taşınarak).

döndürmelerBANANAANANABNANABAANABANNABANAABANANsıralıABANANANABANANANABBANANANABANANANABA012345

2. Alfabetik sıralama: ABANAN, ANABAN, ANANAB, BANANA, NABANA, NANABA. Orijinal dizgi 3. satırda.

sıralıABANANANABANANANABBANANANABANANANABA012345NNBAAABWT = NNBAAA, satır 3

3. Son karakterler (L sütunu): NNBAAA. Çıktı: (NNBAAA, 3). Aynı harfler gruplandı: NN, AAA.

Dizgi Dönüşümleri

BWT Örneği: abraca

S = abraca (başlangıç)abracabracaaracaabacaabrcaabraaabracsıralı matrisaabracabracaacaabrbracaacaabraracaab← L
  • Sıralı matrisin son sütunu: L = caraab.
  • Orijinal "abraca" sıralı matriste 1. satırdadır (0'dan sayarak); ters dönüşüm için bu indis saklanır.
  • İlk sütun (F = aaabcr), L'nin harflerinin sıralanmış hâlidir; L'yi bilmek F'yi de verir.
Doğrudan yöntem n döndürmeyi substring ile üretip Arrays.sort ile sıralar → O(n² log n) zaman, O(n²) bellek. Pratikte sonek dizisinden L[i] = T[SA[i] − 1] ile O(n)'de elde edilir (T sonuna $ eklenmiş metin).

Dizgi Dönüşümleri

BWT'yi Tersine Çevirme (LF Eşlemesi)

iF…L
0$banana
1a$banan
2ana$ban
3anana$b
4banana$
5na$bana
6nana$ba
  • T = banana$ ($ en küçük, tekil) → BWT = annb$aa.
  • F = sırala(L) = $aaabnn.
  • LF kuralı: L'deki k. 'c', F'deki k. 'c' ile aynı karakterdir. i satırındaki L[i], metinde F[i]'den hemen önce gelir.
  • $ ile başlayan 0. satırdan başla, L[i]'yi oku, LF(i) satırına git:
satırlar 0 → 1 → 5 → 2 → 6 → 3 → 4
okunan L: a n a n a b → ters çevir → banana

Sıra sayıları (her karakterin L'de kaçıncı olduğu) önceden hesaplanırsa ters dönüşüm O(n) zaman alır. $ yoksa, BANANA örneğindeki gibi orijinal satır indisi (3) saklanır.

Özet

Özet

KonuHatırlanacaklar
Sözlüksel sırailk farklı karakter karar verir; önek önce gelir; kod sırası ≠ Türkçe alfabe
RadixLSD: sağdan sola kararlı sayarak sıralama, O(W · (N + R)); MSD: soldan, kovalarda özyineleme
Düzenli ifade. * + ? [ ] ^ $ ( ) { } | \d \w \s; bakış ifadeleri karakter tüketmez
FSM(Q, Σ, δ, q₀, F); DFA'da tek geçiş, O(n) tarama; NFA ≡ DFA ≡ düzenli ifade
Levenshtein1 + min(sil, ekle, değiştir), eşitse sol üst; O(m · n)
LCSeşitse sol üst + 1, değilse max(üst, sol); geri izlemeyle dizi
Sonek dizisisıralı sonek indisleri; kaba kuvvet O(n² log n), ikiye katlama O(n log n); arama O(m log n)
BWTsıralı döndürmelerin son sütunu + satır indisi; LF eşlemesiyle geri dönüş; bzip2

Özet

Etkileşimli Simülatörler

Dizgi Sıralama: LSD RadixVirgülle ayrılmış dizgileri sağdan sola, karakter karakter kovalara dağıtarak sıralayın; her geçişte kovaları ve diziyi izleyin.
Dizgi Ayrıştırma: FSMBir tanımlayıcıyı (harf ya da alt çizgiyle başlayan) sonlu durum makinesiyle karakter karakter doğrulayın; geçiş tablosundaki satır vurgulanır.
Dizgi Benzerliği: Levenshteinİki dizgi girin (ör. kitten · sitting); DP tablosunu hücre hücre doldurun ve ekleme, silme, değiştirme maliyetlerini görün.
Dizgi Dönüşümü: BWTTüm döndürmeleri üretin, sıralayın ve son sütunu okuyarak Burrows–Wheeler dönüşümünü adım adım elde edin.

Özet

Sık Yapılan Hatalar

Kod sırasını alfabe sanmak"Zebra" < "apple" ve "şeker" > "zeytin" çıkar. Büyük/küçük harf ve Türkçe için Collator ya da normalleştirme gerekir.
Sayıları dizgi olarak sıralamak"10" < "9" olur. Sayısal sıra için tamsayıya çevirin ya da sıfırla aynı uzunluğa getirin.
LSD'de kararsız alt sıralamaHer geçiş kararlı olmalıdır; aksi hâlde önceki geçişlerin sırası bozulur. Sayarak sıralamada yerleştirme sondan başa yapılır.
Kaçışsız nokta, açgözlü .*a.b "a+b" ile de eşleşir; <.*> tüm satırı yutar. \. ve tembel .*? kullanın. (a+)+$ gibi ifadeler üstel geri izlemeye yol açar.
DP tablosunda indis kaymasıTablo (m+1) × (n+1)'dir; D[i][j] için charAt(i − 1) karşılaştırılır. İlk satır/sütunu başlatmamak sonucu bozar.
Alt dizi ile alt dizgiyi karıştırmakLCS ardışıklık istemez; en uzun ortak alt dizgi ister. BWT'de de satır indisini ya da $'ı saklamayı unutmak dönüşümü geri alınamaz kılar.

Özet

Örnek Problemler

  1. "10", "9", "100", "2" dizgilerini sözlüksel sıraya koyun.
  2. [329, 457, 657, 839, 436, 720, 355] dizisine LSD radix uygulayın; her geçişten sonraki diziyi yazın.
  3. ^\d{3}-\d{4}$ ifadesi "555-1234", "5551234", "55-12345" dizgilerinden hangileriyle eşleşir?
  4. Levenshtein("sunday", "saturday") kaçtır?
  5. LCS("ABCBDAB", "BDCABA") uzunluğu kaçtır? Bir LCS yazın.
  6. "kayak" dizgisinin BWT'sini ve orijinal satır indisini bulun.
Cevapları göster
  1. "10" < "100" < "2" < "9" ("10", "100"ün önekidir).
  2. 1: 720, 355, 436, 457, 657, 329, 839 · 2: 720, 329, 436, 839, 355, 457, 657 · 3: 329, 355, 436, 457, 657, 720, 839.
  3. Yalnızca "555-1234".
  4. 3: "a" ve "t" ekle (satunday), n → r değiştir (saturday).
  5. 4; örneğin BCBA (BDAB ve BCAB de olur).
  6. Sıralı döndürmeler: akkay, ayakk, kayak, kkaya, yakka → BWT = ykkaa, indis 2.

Özet

Alıştırmalar

  1. MSD radix sıralamayı özyinelemeli olarak yazın.
  2. Türkiye cep telefonu biçimini (0532 123 45 67) doğrulayan bir düzenli ifade yazın.
  3. İkili dizgilerde 1 sayısı çift olanları kabul eden bir DFA çizin ve geçiş tablosunu yazın.
  4. Levenshtein'ı yalnızca iki satırlık bellekle, O(min(m, n)) ek alanla hesaplayın.
  5. Sayı ayrıştıran FSM "… ve 5." girdisinde "5." yazdırır. Makineyi düzeltin.
  6. "mississippi" metninin sonek dizisini bulun.
Cevaplar / ipuçları
  1. sirala(a, alt, ust, d): d. karaktere göre kovalara dağıt (sonu biten dizgiler −1 kovası), her kova için sirala(…, d + 1).
  2. ^0\d{3} \d{3} \d{2} \d{2}$ (yalnızca 05 için: ^05\d{2} …).
  3. İki durum: Çift (başlangıç, kabul) ve Tek. 0: aynı durumda kal; 1: Çift ↔ Tek.
  4. onceki ve simdi dizileri; her satır sonunda yer değiştirin. Kısa dizgiyi sütun yapın.
  5. Yazdırmadan önce tampon '.' ile bitiyorsa son karakteri silin (ya da noktayı ancak ardından rakam gelirse ekleyin).
  6. SA = [10, 7, 4, 1, 0, 9, 8, 6, 3, 5, 2] (i, ippi, issippi, ississippi, mississippi, pi, ppi, sippi, sissippi, ssippi, ssissippi).

Özet

Kaynaklar

  • Sedgewick ve Wayne, Algorithms, 4. baskı, 2011 (5.1 String Sorts, 5.4 Regular Expressions).
  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022 (LCS, dizgi eşleme otomatları).
  • Hopcroft, Motwani ve Ullman, Introduction to Automata Theory, Languages, and Computation, 3. baskı, 2006.
  • V. I. Levenshtein, "Binary codes capable of correcting deletions, insertions, and reversals", Soviet Physics Doklady 10(8), 1966.
  • R. A. Wagner ve M. J. Fischer, "The String-to-String Correction Problem", Journal of the ACM 21(1), 1974.
  • U. Manber ve G. Myers, "Suffix Arrays: A New Method for On-Line String Searches", SIAM Journal on Computing 22(5), 1993.
  • M. Burrows ve D. J. Wheeler, "A Block-sorting Lossless Data Compression Algorithm", DEC SRC Research Report 124, 1994.
  • J. E. F. Friedl, Mastering Regular Expressions, 3. baskı, O'Reilly, 2006; Java java.util.regex.Pattern belgeleri.

Son

Bölüm 5: Dizgi Algoritmaları (2)
Sonraki bölüm: Bölüm 5: Trie Veri Yapısı
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.