• Sonuç bulunamadı

2. VERİ SIKIŞTIRMA ALGORİTMALARI

2.2. Sözlük Tabanlı Teknikler

2.2.3. Dinamik sıkıştırma yaklaşımı

2.2.3.2. LZ78 sıkıştırma algoritması

LZ77 sıkıştırma algoritmasının zayıf yanı küçük bir pencere kullanmasıdır. Bu da metnin ilerleyen kısımlarında değerli eşleşmelerin göz ardı edileceği anlamını taşımaktadır. Örneğin bir kitabın ilk bölümlerinde geçen 10 karakterlik bir bölüm, kitabın son bölümlerinde de geçiyorsa ve aradaki mesafe eğer arama tamponunun boyutundan büyük ise eşleşme bulunamayacaktır. Ancak eğer metindeki o 10 karakterlik katar bir sözlükte yer almış olursa eşleşmeler gözden kaçmayacak ve daha güzel sıkıştırma oranları elde edilmiş olacaktır. LZ77 sıkıştırma algoritmasının temel mantığı daha çok görüleni bulmaktan ziyade, son geçenleri bulmaktır.

LZ77 sıkıştırma algoritmasındaki ikinci zafiyet dizginin kısıtlı bir bölümünün eşleşme olarak nitelendirilebileceğidir. En uzun eşleşme ancak ileri tamponun boyuna yaklaşık olarak eşittir.

Bu problemleri aşmanın bir yolu, tampon boyutlarını büyütmek olsa da zaman açısından oldukça yüksek bir maliyeti vardır.

Ziv ve Lempel bu problemlerle karşılaştıkları için bir başka sözlük tabanlı sıkıştırma yöntemi geliştirdiler. Buna LZ78 adını vererek “Compression of Individual Sequences via Variable-Rate Coding” isimli makalelerinde 1978 yılında yayınladılar.

LZ78 sıkıştırma algoritması, LZ77 sıkıştırma algoritmasının pencere yaklaşımından sıyrılıp, potansiyel olarak sınırsız ve daha önceden geçmiş olan katarlardan oluşan bir sözlük yaklaşımı benimsemiştir. LZ77 sıkıştırma algoritmasına benzer olarak aynı anlama gelen parametreler içeren kod kelimeleri üretir. LZ78 sıkıştırma algoritmasının ürettiği kod kelimesi bir katara karşılık gelen kod ve bir karakter içeren bir kod kelimesine sahiptir. LZ77 sıkıştırma algoritmasından farklı olarak katar uzunluğu parametre olarak verilmez. Çünkü kod çözücü bu uzunluğu bilmektedir.

LZ78 sıkıştırma algoritmasında hem kodlayıcı hem de kod çözücü neredeyse boş bir sözlükle işe başlamaktadır. Sözlükte yer alan tek eleman NULL karakteridir. Her karakter okunduğunda, eldeki katara eklenir. Bu işlem katar sözlükte bir eşleşme gerçekleştirdiği sürece devam eder.

Eşleşme gerçekleşmediği anda sözlüğe ekleme işlemi yapılır. Son karakter okunana kadar sözlükte eşleşme gerçekleştirilmiştir. Son karakter okunduğunda bu eşleşme durumu ortadan kalkmıştır. İşlenen eldeki katar son eşleşen katar ve bir ilave karakter olarak ifade edilir. Bu da LZ77 sıkıştırma algoritmasının ürettiği çıktıdır.

Ancak bu noktada LZ78 sıkıştırma algoritması ilave bir adım kullanmaktadır. Yeni karakter içeren yeni katar sözlüğe eklenmektedir. Katar bir daha geçtiğinde daha uzun bir eşleşme ortaya çıkabilecektir.

Boş katar her zaman 0 indeksli sözlük elemanı ile eşleşecektir. Bu sebeple bir karakterle ilk defa karşılaşıldığında, 0 katarı artı bir karakter olarak kodlanacaktır. Karakter bir daha görüldüğünde katar parçası olarak değerlendirilecektir.

Kodlayıcı çıktısının bir örneği çizelge 2.8’de verilmiştir. LZ78 sıkıştırma algoritması neredeyse boş sözlükle işe başlar, bu sebeple ilk okunan “D” karakteri sözlükte herhangi bir eşleşemeye uymaz. Bu durumda kodlayıcı katar/karakter çifti olarak 0 ve “D” kodlar. Burada 0 indeksi boş katara ayrılmıştır.

Çizelge 2.8 Örnek metin için üretilen LZ78 çıktıları

Çıktı Katarı Çıktı Karakteri Kodlanan Katar

0 D D 0 A A 1 _ D_ 1 A DA 4 _ DA_ 4 D DAD 1 Y DY 0 _ _ 6 O DADO

İlk İki karakter olan “D” ve “A” daha önceden görülmemişlerdir. Bu sebeple 0+karakter çifti olarak kodlanacaktır. 1 numaralı indekse “D”, 2 numaralı indekse de “A” ilave edilir. Üçüncü karakter olan “D” okunduğunda sözlükte yer aldığı görülmektedir. Sonraki karakter olan “_” karakteri de okunur ve katara eklenir. “D_” sözlükte yer almadığı için üretilen kod, eşleşen “D” karakterinin indeksi ve “_” karakterini içeren (1,”_”) olur.

Kodlama devam ettikçe sözlük oluşur ve oldukça büyük parçaları içermeye başlar. Sözlükteki girdiler alfabetik sırada olacağı için girdiler oldukça hızlı olarak üretilebilir. Örnek metindeki 19 karakter okunup kodlandığında sözlük aşağıdaki gibi olur.

0 “” 1 “D” 2 “A” 3 “D_” 4 “DA” 5 “DA_” 6 “DAD” 7 “DY” 8 “_” 9 “DADO”

LZ77 sıkıştırma algoritmasında olduğu gibi LZ78 sıkıştırma algoritmasında da sözlük boyutu isteğe bağlı olarak seçilebilir. Ancak sözlük boyutunu seçerken dikkat edilmesi gereken iki husus mevcuttur. İlk olarak, kod kelimesi için kullanılacak olan bit sayısı düşünülmelidir. İkinci ve daha önemli olarak da sözlüğü yönetmek için gerekli olan CPU zamanı düşünülmelidir.

Teoride LZ78 sıkıştırma algoritması, sözlük boyutu büyüdükçe daha güzel oranlarda sıkıştırma yapmaktadır. Ancak bu durum sadece girdi metninin boyutu sonsuza yaklaşırken yani oldukça büyük olması durumunda gerçekleşmektedir. Büyük kod kelimeleri içeren küçük boyutlu metinler aynı derecede kötü etkilenmektedir.

LZ78 sıkıştırma algoritması ile ilgili olarak gerçek problem sözlüğü yönetmektir. Eğer sözlük indeksi olarak 16 bit uzunluklu kod kullanılırsa, NULL kodu da dâhil olmak üzere 65535 katar sözlükte yer alabilir. Katarlar son derece uzun olabilir. Hatta bir katarın mümkün 65536 alt katarını içerebilir.

Bu katarlar ağaçlar üzerinde tutulur. Ağaç kök nodunda NULL katarını tutmaktadır. NULL katarına eklenen her yeni karakter ağacın yeni bir dalıdır. LZ78 sıkıştırma algoritması için örnek bir ağaç şekil 2.12’de verilmiştir.

Şekil 2.12 LZ78 sözlük ağacı

Şekil 2.12’de gösterilen ağaç, 19 harflik örnek metin işlendikten sonra oluşmuş olan ağaçtır. Ağacı yönetmenin en büyük zorluğu da her noddan çıkan dallar sayesinde ağacın büyümesidir. 8-bit alfabeli ikili dosyalar sıkıştırılırken, her noddan çıkabilecek

256 mümkün dal mevcuttur. Bunları tutmak için de işaretçiler veya diziler kullanılabilir. Ancak hepsi dolu olamayacağı için oldukça büyük bir yer israfı söz konusudur. Bunun yerine ağaç dalı olarak değil, ağaç dalına referans veren indeksler listesi olarak tutulurlar. Bu belirgin ölçüde problemi çözse de oldukça yavaş bir yöntemdir.

Şekil 2.12’deki gibi bir ağaçta, var olan bir katarla sözlüğü karşılaştırmak son derece kolaydır. Normal olarak ağacı dolaşmak gibi bir işlemdir. Eğer bir ağaç nodunda katar tüketilirse orada bir eşleşme söz konusudur.

LZ78 sıkıştırma algoritmasının LZ77 sıkıştırma algoritmasına göre olumsuz bir yanı da kod çözücünün de aynı ağacı kod çözme esnasında oluşturmasının gerekmesidir. LZ77 sıkıştırma algoritmasında sözlük indeksi kendinden önce geçmiş bir katara işaret etmektedir. Ancak LZ78 sıkıştırma algoritmasında bu indeks bir sözlük ağacı indeksidir. Bu sebepten kodlayıcı gibi kod çözücü de aynı ağacı aynı mantıkla oluşturmalıdır.

Sözlük, boyutuna bağlı olarak kısa zamanda veya daha uzun zamanda dolacaktır. Eğer 16-bit kod kullanılıyorsa, sözlük 65535 katar işlendikten sonra dolacaktır.

Bu problemin üstesinden gelmek için birkaç yöntem mevcuttur. Ama en geçerli yöntem sözlük dolduktan sonra yeni nodlar eklemeyi bitirmektir. [Nelson ve Gailly,1995]