Materyalden Adapte et karıştırabilir, aktarabilir ve eserin üzerine inşa edebilirsiniz.

Ebat: px
Şu sayfadan göstermeyi başlat:

Download "Materyalden Adapte et karıştırabilir, aktarabilir ve eserin üzerine inşa edebilirsiniz."

Transkript

1 Açık Veri Yapıları Java ile Baskı: 0.1F Yazar: Pat Morin Telif Hakları Açık Veri Yapıları Java ile Pat Morin tarafından yazılmıştır. Her hakkı saklıdır. Kitabın orijnali adresinde bulunmaktadır. Bu kitap ile belirtilen hüküm ve koşullara tabi olarak Türkçe ye çevrilmiştir. Bu eseri her boyut ve formatta paylaşabilir kopyalayabilir ve çoğaltabilirsiniz. Materyalden Adapte et karıştırabilir, aktarabilir ve eserin üzerine inşa edebilirsiniz. her türlü amaç için, ticari amaç da dahil Lisansör lisans şartlarını takip ettiğiniz sürece özgürlükleri iptal edemez. Bu kitabın Türkçe çevirisi de aynı lisanslamaya tabidir.

2 İÇİNDEKİLER TABLOSU BÖLÜM 1 7 Giriş Verimlilik Gereksinimi Arayüzler Kuyruk, Yığıt ve İki Başlı Kuyruk Arayüzleri Liste Arayüzü : Doğrusal Diziler UKüme Arayüzü : Sıralı Olmayan Kümeler SKüme Arayüzü : Sıralı Kümeler Matematiksel Zemin Üslüler ve Logaritmalar Faktöryeller Asimptotik Gösterim Rasgele Sıralama ve Olasılık Hesaplama Modeli Doğruluk, Zaman Karmaşıklığı ve Alan Karmaşıklığı Kod Örnekleri Veri Yapıları Listesi Tartışma ve Alıştırmalar 31 BÖLÜM 2 35 Dizi-Tabanlı Listeler Dizi Yığıtı: Dizi Kullanan Hızlı Yığıt İşlemleri Temel Bilgiler Büyültme ve Küçültme Özet Hızlı Dizi Yığıtı: Optimize Dizi Yığıtı Dizi Kuyruğu : Dizi-Tabanlı Kuyruk Özet Dizi İki Başlı Kuyruk: Bir Dizi Kullanan Hızlı İki Başlı Kuyruk İşlemleri Özet Çifte Dizi İki Başlı Kuyruk: İki Yığıt tan Bir İki Başlı Kuyruk Oluşturulması Özet 56 2

3 2.6 Kök Dizi Yığıt: Alan Kriteri Verimli Olan Bir Dizi Yığıt Uygulaması Büyültme ve Küçültmenin Analizi Alan Kullanımı Özet Karekökleri Hesaplamak Tartışma ve Alıştırmalar BÖLÜM 3 70 Bağlantılı Listeler TBListe: Tekli-Bağlantılı Liste Kuyruk İşlemleri Özet ÇBListe: Çifte-Bağlantılı Liste Ekleme ve Çıkarma Özet AVListe: Alan-Verimli Liste Alan Gereksinimleri Elemanların Bulunması Elemanların Eklenmesi Elemanların Silinmesi yayıl (u) ve birarayagetir (u) Yöntemlerinin Amortize Edilmiş Analizi Özet Tartışma ve Alıştırmalar BÖLÜM 4 93 Sekme Listeleri Temel Yapı 4.2 Sıralı Küme Sekme Listesi : Verimli bir Sıralı Küme Özet Liste Sekme Listesi: Verimli Rasgele Erişim Listesi Özet Sekme Listelerinin Analizi Tartışma ve Alıştırmalar 108 3

4 BÖLÜM Karma Tabloları Zincirleme Karma Tablo: Zincirleme Aracılığıyla Adresleme Çarpımsal Karma Yöntemi Özet Doğrusal Karma Tablo: Doğrusal Yerleştirme Doğrusal Yerleştirme Analizi Özet Listeleme Karma Yöntemi Karma Kodları Temel Veri Türleri için Karma Kodları Bileşik Nesneler için Karma Kodları Diziler ve Dizeler için Karma Kodları Tartışma ve Alıştırmalar BÖLÜM İkili Ağaçlar İki Dallı Ağaç: Temel İkili Ağaç Özyinelemeli Algoritmalar İkili Ağaçta Sıralı-Düğüm Ziyaretleri Serbest Yükseklikli İkili Arama Ağacı Arama Ekleme Silme Özet Tartışma ve Alıştırmalar BÖLÜM Rasgele İkili Arama Ağaçları Rasgele İkili Arama Ağaçları Önerme 7.1 in Kanıtı Özet Treap: Randomize İkili Arama Ağaçları Özet Tartışma ve Alıştırmalar 4

5 BÖLÜM Günah Keçisi Ağaçları Günah Keçisi Ağacı: Kısmi Yeniden Oluşturmalı İkili Arama Ağacı Doğruluk Analizi ve Çalışma Zamanı Özet Tartışma ve Alıştırmalar BÖLÜM Kırmızı-Siyah Ağaçlar Ağacı Yaprak eklenmesi Yaprak silinmesi Kırmızı-Siyah Ağacı: 2-4 Ağacı ile Benzeşen Kırmızı-Siyah Ağaçlar ve 2-4 Ağaçlar Kırmızı-Siyah Ağaçlarda Sola-dayanım Ekleme Silme Özet Tartışma ve Alıştırmalar 209 BÖLÜM Yığınlar İkili Yığın: Bir Örtülü İkili Ağaç Özet Karışık Yığın: Rasgele Karışık Yığın merge(h1, h2) Analizi Özet Tartışma ve Alıştırmalar BÖLÜM Sıralama Algoritmaları Karşılaştırmaya-Dayalı Sıralamalar Birleştirerek-Sıralama Hızlı-Sıralama Yığın-Sıralama Karşılaştırmaya Dayalı Sıralama için Alt-Sınır

6 11.2 Sayma Sıralama ve Taban Sıralaması Sayma Sıralaması Taban-Sıralaması Tartışma ve Alıştırmalar BÖLÜM Grafikler Bitişiklik Matrisi: Bir Grafiğin Matris ile Gösterimi Bitişiklik Listeleri: Liste Derlemi olarak Grafik Grafik Ziyaretleri Enine-Arama İlkin-Derinliğine Arama Tartışma ve Alıştırmalar BÖLÜM Tamsayılar için Veri Yapıları İkili Sıralı Ağaç: Sayısal Arama Ağacı X-Hızlı Sıralı Ağaç: Çifte-Logaritmik Zamanda Arama Y-Hızlı Sıralı Ağaç: Çifte-Logaritmik Zamanlı Sıralı Küme Tartışma ve Alıştırmalar 281 BÖLÜM Dış Bellek Aramaları Blok Deposu 14.2 B-Ağaçları Arama Ekleme Silme B-Ağaç ların Amortize Analizi Tartışma ve Alıştırmalar KAYNAKÇA 308 6

7 Bölüm 1 Giriş Dünyadaki bilgisayar bilimleri öğretim programlarının tümünün bir parçası olarak veri yapıları ve algoritmalar üzerine bir ders bulunur. Veri yapıları bu kadar önemlidir, her gün, hafta ve ay aynı zamanda bizi tehlike, zarar ve başarısızlıktan korur; böylece daha başarılı oluruz. Pek çok multi-milyon ve multi-milyar liralık şirketler ihtiyaçları veya gereksinimlerine uygun birçok veri yapısı etrafında inşa edilmişlerdir. Bu nasıl olabilir? Eğer biraz düşünürsek, veri yapıları ile belirli bir süre boyunca çok sık ya da her zaman etkileşim içinde olduğumuzu anlarız. Dosya açmak: Dosya sistemine ait veri yapıları bir dosyanın parçalarını diskte bulmak için kullanılır, böylece o dosyaya erişebiliriz. Bu kolay değildir; diskler yüzlerce milyon blok içerir. Dosyanızın içeriği bunlardan herhangi biri üzerinde saklanmış olabilir. Telefonunuzda kayıtlı olan bir kişiye bakmak: Siz aramayı/yazmayı bitirmezden önce kısmi bilgiye dayalı olarak kişi listesindeki bir telefon numarasını aramak için de bir veri yapısı kullanılır. Bu kolay değildir; telefonuzda pek çok insan hakkında bilgiler kayıtlı olabilir - telefon ya da e-posta yoluyla temas etmiş olduğunuz herkes - ve telefonunuzun çok hızlı bir işlemcisi ya da belleği yoktur. En sevdiğiniz sosyal ağınıza giriş yapmak: Ağ sunucuları hesap bilgilerinize bakmak için giriş bilgilerinizi kullanır. Bu kolay değildir; en popüler sosyal ağlar yüzlerce milyon aktif kullanıcı içerir. Web araması yapmak: Arama motoru, arama terimlerinizi içeren web sayfalarını bulmak için veri yapılarını kullanır. Bu kolay değildir; Internet üzerinde 8,5 milyarın üzerinde web sayfası vardır ve her sayfa pek çok potansiyel arama terimlerini içerir. 7

8 Telefon acil durum hizmetleri (1-5-5): Polis arabaları, ambulanslar ve itfaiye araçları gecikmeden adresinize gönderilsin diye acil servis şebekeleri telefon numaralarını adreslere eşleştiren bir veri yapısı içinde sizin telefon numaranızı arar. Bu önemlidir, çağrıyı yapan kişinin tam adresini vermesi mümkün olmayabilir ve bir gecikme ölüm kalım arasındaki fark anlamına gelebilir. 1.1 Verimlilik Gereksinimi Bir sonraki bölümde, en sık kullanılan veri yapıları tarafından desteklenen işlemlere bakacağız. Biraz programlama deneyimi olan herkes bu işlemleri doğru olarak gerçekleştirmenin zor olmadığını görecektir. Muhtemelen bir dizi veya bir bağlantılı listede veriyi saklayabiliriz ve dizi veya listedeki tüm elemanlar üzerinden yineleme yaparak örneğin bir öğeyi ekleyebilir veya kaldırabiliriz. Bu tür bir uygulama kolaydır, ancak çok verimli değildir. Bu gerçekten önemli mi? Bilgisayarlar hızlı ve gitgide daha hızlı hale gelmektedir. Belki anlaşılması kolay olan uygulama yeterince iyidir. Öğrenmek için biraz taslak hesaplama yapalım. İşlem sayısı: 1 milyon (106) elemanlı olan orta ölçekte veri seti kullanan bir uygulama düşünün. Bu uygulamanın en az bir kez her bir elemanı aramak isteyeceğini varsaymak, çoğu uygulama için makuldur. Bu demektir ki, bu veriler içinden en az 1 milyon (106) arama yapmayı bekleyebiliriz. Her bir arama için 106 inceleme yapılacaksa, bu toplam 106 x 106 = 1012 (bir trilyon) arama verir. İşlemci hızları: Çok hızlı bir masaüstü bilgisayar bile saniyede bir milyardan fazla (109) yazma işlemi yapamaz.1 Bu demektir ki, bu uygulama en az 1012 / 109 = 1000 saniye, ya da yaklaşık 16 dakika ve 40 saniye alacaktır. Onaltı dakika bilgisayar zamanı için bir ebediyettir, ancak kahve molası vermek için dışarıya yönelen bir kişi ona katlanabilir. Büyük veri setleri: Şimdi 8,5 milyarın üzerinde web sayfasını endeksleyen, Google gibi bir şirket düşünün. Bizim hesaplamalara göre, bu veriler üzerinde yapılacak her türlü sorgu en az 1 Bilgisayar hızları çoğu birkaç gigahertz (saniyede milyarlarca devir) civarındadır ve her işlem genellikle birkaç devir alır. 8

9 8,5 saniye sürer. Ancak bu durumda olmadığımızı zaten biliyoruz; web aramaları 8,5 saniyeden çok daha az sürede tamamlanıyor, ve belirli bir sayfanın kendilerine endeksli sayfaların içinde olup olmadığını sormaktan çok daha karmaşık sorguları yapıyorlar. Google, saniyede yaklaşık sorgu alır, bu onların işi yürütebilmesi için en az x 8,5 = çok hızlı sunucuya gereksinim duydukları anlamına gelir. Çözüm: Bu örnekler veri yapılarının anlaşılması kolay olan uygulamalarındaki, n, veri yapısındaki eleman sayısının ve, m, veri yapısı üzerinde gerçekleştirilen işlem sayısının, özellikle her ikisi de büyük olduğunda iyi ölçek sağlamadığını bize söylemektedir. Bu durumda, zaman (diyelim ki, makine komutu cinsinden ölçüldüğünde) yaklaşık olarak n x m olacaktır. Çözüm, tabii ki, her işlemin her veri elemanını kontrol etmesini gerektirmeyecek şekilde veri yapısı içindeki verileri dikkatle organize etmektir. Bu ilk bakışta imkansız gözükmesine rağmen, veri yapısı içinde depolanmış eleman sayısından bağımsız olacak şekilde, sadece ortalama iki elemana bakarak arama yapılabilen veri yapılarını göreceğiz. Saniyede milyar komut çalıştırabilen bilgisayarımızda, bir milyar eleman (veya bir trilyon, bir katrilyon, ve hatta bir kentilyon) içeren bir veri yapısı içinde arama yapmak sadece 0, saniye alır. Elemanları sıralı bir şekilde tutan ve bir işlem sırasında kontrol edilen eleman sayısının, veri yapısındaki eleman sayısının bir fonksiyonu olarak, çok yavaş büyüdüğü gerçekleştirimleri de göreceğiz. Örneğin, herhangi bir işlem sırasında en fazla 60 elemanı kontrol edecek şekilde bir milyar elemanı sıralı olarak tutabiliriz. Saniyede milyar komut çalıştırabilen bilgisayarımızda, bu işlemler 0, saniye alır. Bu bölümün kalan kısmında kısaca kitabın geri kalanı boyunca kullanılan bazı temel kavramlar yorumlanacaktır. Bölüm 1.2, bu kitapta anlatılan veri yapılarının tümü tarafından gerçekleştirilen arayüzleri açıklamaktadır ve okunması gerekli olarak dikkate alınmalıdır. Kalan bölümler şunları tartışmaktadır: üsler, logaritma, faktöriyel, asimptotik (büyük-oh) gösterimi, olasılık ve randomizasyon dahil olmak üzere bazı matematiksel incelemeler; hesaplama modeli; 9

10 doğruluk, yürütme zamanı ve alanı; kalan bölümlere genel bir bakış, ve örnek kod ve dizgi kuralları. Bu alanlarda birikim sahibi olan veya olmayan okuyucular şimdi onları kolayca atlayabilir ve gerekirse daha sonra onlara tekrar geri dönebilir. 1.2 Arayüzler Veri yapılarını tartışırken, bir veri yapının arayüzü ile gerçekleştirimi arasındaki farkı anlamak önemlidir. Bir arayüz bir veri yapısının ne yaptığını açıklarken, gerçekleştirimi veri yapısının bunu nasıl yaptığını açıklar. Bazen soyut veri türü olarak da adlandırılan arayüz, bir veri yapısı tarafından desteklenen işlemlerin kümesini ve bu işlemlerin semantiğini, yani anlamını, tanımlar. Bir arayüz bize veri yapısının bu işlemleri nasıl gerçekleştirdiğine dair hiçbir şey söylemez; sadece desteklenen işlemlerin bir listesini ve her işlemin ne tür argümanları kabul ettiğini ve döndürdükleri değer hakkında belirtimler sağlar. Bir veri yapısı gerçekleştirimi, diğer taraftan, veri yapısının iç gösterimini ve aynı zamanda veri yapısı tarafından desteklenen işlemleri uygulamaya koyan algoritmaların tanımlarını içerir. Bu nedenle, tek bir arayüzün birçok uygulaması olabilir. Örneğin biz, Bölüm 2 de, dizileri kullanarak Liste arayüzü uygulamalarını görürken, Bölüm 3 te işaretçi-tabanlı veri yapılarını kullanarak Liste arayüzü uygulamalarını göreceğiz. Her ikisi de aynı arayüzü, Liste yi uygular, ama farklı şekillerde. 10

11 1.2.1 Kuyruk, Yığıt ve İki Başlı Kuyruk Arayüzleri Kuyruk arayüzü kendisine eleman ekleyebileceğimiz ve sonraki elemanı kaldırabileceğimiz bir elemanlar topluluğunu simgeler. Daha kesin olarak, Kuyruk arayüzü tarafından desteklenen işlemler şunlardır: ekle (x): Kuyruğa x değerini ekler. sil (x): Sonraki (daha önceden eklenen) y değerini, kuyruktan kaldırır ve y değerini döndürür. sil () işleminin hiçbir argüman almadığına dikkat edin. Kuyruk un kuyruklama disiplini hangi elemanın kaldırılması gerektiğine karar verir. En yaygın olarak FIFO (ilk-giren-ilkçıkar), öncelik kuyruğu, ve LIFO (son-giren-ilk-çıkar) dahil olmak üzere birçok olası kuyruk disiplinleri vardır. Şekil 1.1 'de gösterilen bir FIFO (ilk-giren-ilk-çıkar) Kuyruk u, elemanları onların eklendiği sıranın aynı sırasıyla kaldırır. Bunu bir bakkalın kasasında çalışan kuyruğa (veya sıraya) benzetebiliriz. Bu en yaygın Kuyruk türüdür, bu nedenle FIFO sıfatı genellikle ihmal edilir, kullanılmaz. Diğer metinlerde genellikle, FIFO Kuyruğu üzerindeki ekle (x) ve sil() işlemleri sırasıyla kuyruğa koy (x) ve kuyruktan kaldır () olarak adlandırılır. Şekil 1.2 'de gösterilen öncelik kuyruğu, her zaman, en küçük elemanı siler, bağları buna uygun olacak şekilde kırar. Bunu bir hastanenin acil serviste hastalara servis vermesine benzetebiliriz. Hastalar geldikçe değerlendirilir ve daha sonra bir bekleme odasına yerleştirilir. Bir doktor müsait olduğunda o ilk olarak yaşam tehditi en fazla bulunan hasta ile ilgilenir. Öncelik kuyruğu üzerindeki sil () işlemi diğer metinlerde genellikle silmin () olarak adlandırılır. Çok yaygın bir kuyruk disiplini de Şekil 1.3 'de gösterildiği gibi LIFO (son-giren-ilk-çıkar) disiplinidir. LIFO Kuyruğunda, en son eklenen eleman silinir. Bunu en iyi tabakların üst üste dizildiği bir tabak yığıtı şeklinde görselleştirebiliriz. Yeni bir tabağı yığıtın en üstüne dizerken, yine tabak çıkarırken yığıtın en üstünden çıkarırız. Bu yapı çok yaygındır ve Yığıt adı altında incelenir. Bir Yığıt tartışılırken çoğu zaman, ekle () ve sil () adları yığ() ve 11

12 yığıttan kaldır () olarak değiştirilir, bunun nedeni LIFO ve FIFO kuyruk disiplinleri ile karışmasının önüne geçmektir. İki Başlı Kuyruk, hem FIFO Kuyruğu ve hem de LIFO Kuyruğu nun (Yığıt) genellenmiş bir halidir. Önü ve arkası bulunan elemanlardan oluşan bir diziyi gösterir. Elemanlar dizinin başına veya sonuna eklenebilir. İki Başlı Kuyruk işlemlerinin adları da kendi kendilerini açıklayıcıdır: başaekle(x), baştansil (), sonaekle (x), sondansil (). Şunu belirtmeliyiz ki, bir Yığıt sadece başaekle (x) ve baştansil () kullanılarak uygulanabilirken, bir FIFO kuyruk da sonaekle (x) ve sondansil () kullanılarak uygulanabilir. 12

13 1.2.2 Liste Arayüzü : Doğrusal Diziler Bu kitapta FIFO Kuyruk, Yığıt, ya da İki Başlı Kuyruk arayüzleri hakkında çok az konuşacağız. Bunun nedeni bu arayüzlerin Liste arayüzü tarafından kapsanmasıdır. Şekil1.4 te gösterilmiş olan bir Liste, x0 xn-1, değerlerinden oluşan bir diziyi simgeler. Liste arayüzü aşağıdaki işlemleri içerir: 1. boyut () : Listenin uzunluğunu, n, döndür. 2. al (i) : xi değerini döndür. 3. belirle (i, x) : xi değerini x e eşitle. 4. ekle (i, x) : x1 xn-1 in yerini değiştirerek i konumuna x değerini yerleştir; Her j { n-1,, i } için xj+1 = xj eşitle, n i 1 artır, ve xi = x eşitle. 5. sil (i) : xi+1 xn-1 in yerini değiştirerek xi değerini kaldır; Her j { i,, n-2 } için xj = xj+1 eşitler, n i 1 azalt. Dikkat ediniz ki, bu işlemler İki Başlı Kuyruk arayüzünü uygulamak için de kesinlikle yeterlidir. başaekle (x) ekle (0, x) baştansil () sil (0) sonaekle (x) ekle (boyut (), x) sondansil () sil (boyut () 1) Daha sonraki bölümlerde Yığıt, İki Başlı Kuyruk ve FIFO Kuyruk arayüzlerini tartışmayacağımıza rağmen, Yığıt ve İki Başlı Kuyruk terimleri bazen Liste arayüzünü 13

14 gerçekleştiren veri yapılarını adlandırmakta kullanılmaktadır. Bu durum, bu veri yapılarının Yığıt veya İki Başlı Kuyruk arayüzlerini çok verimli uygulamak için kullanılabilir olması gerçeğini vurgulamaktadır. Örneğin, DiziİkiBaşlıKuyruk sınıfı tüm İki Başlı Kuyruk işlemlerini sabit zamanda gerçekleştiren bir Liste arayüzünün uygulamasıdır UKüme Arayüzü : Sıralı Olmayan Kümeler UKüme arayüzü matematiksel bir diziyi taklit eden tekil elemanlardan oluşan ve sıralı olmayan bir kümeyi simgeler. Bir UKüme n farklı eleman içerir; hiçbir eleman bir kereden fazla görünmez; ve elemanlar hiçbir belirli sırada sıralanmamıştır. Bir UKüme aşağıdaki işlemleri destekler: 1. boyut () : Kümedeki eleman sayısı olan, n, döndür. 2. ekle (x) : Kümede zaten mevcut değilse x elemanını kümeye ekle; Kümede hiçbir y elemanı yoktur ki x y ye eşit olsun koşuluyla x elemanını kümeye ekle. x kümeye eklendiği takdirde doğru döndür ve aksi takdirde yanlış döndür. 3. sil (x) : Kümeden x i kaldır; Kümede öyle bir y elemanı bul ki x y ye eşit olsun ve bu durumda y yi sil. Bu tür bir eleman yoksa null, varsa y döndür. 4. bul (x) : Kümede varsa, x elemanını bul; Kümede öyle bir y elemanı bulur ki y x e eşit olsun. Bu tür bir eleman yoksa null, varsa y döndür. Bu tanımlar sildiğimiz veya bulduğumuz değer olan x ile silebileceğimiz veya kaldırabileceğimiz değer olan y arasındaki ayrımı biraz belirsiz yapıyor. Bunun nedeni x ve y eşit olarak değerlendirilirse de aslında farklı nesneler olabilir.2 Böyle bir ayrım yararlıdır, çünkü anahtarları değerlerle eşleştiren sözlük veya eşlemlerin oluşturulmasına izin verir. Bir sözlük / eşlem oluşturmak için, her biri bir anahtar ve bir değer içeren Çiftler diye adlandırılan bileşik nesneleri oluşturmak gerekir. İki Çift, anahtarları eşitse eşit olarak kabul edilir. (k, v) çiftini bir UKüme de saklarsak ve daha sonra x = (k, null) çiftini kullanarak 2 Bu Java'da, sınıfın eşittir (y) ve hashcode () yöntemleri geçersiz kılınarak yapılır. 14

15 bul (x) yöntemini çağırırsak, sonuç y = (k, v) olacaktır. Diğer bir deyişle, sadece anahtar, k değeri verilerek, v yi geri kazanmak mümkündür SKüme Arayüzü : Sıralı Kümeler SKüme arayüzü sıralanmış elemanların bir kümesini simgeler. SKüme elemanlarının tamamı sıralı halde saklanır, böylece herhangi iki eleman, x ve y karşılaştırılabilir. Kod örneklerinde bu, tanımı aşağıdaki gibi olan ve karşılaştır (x, y) adı verilen bir yöntemle yapılacaktır. SKüme, boyut (x), ekle(x), sil (x) yöntemlerini UKüme arayüzüyle tam olarak aynı anlamda olacak şekilde destekler. Bir UKüme ve SKüme arasındaki fark bul (x) yöntemindedir : 4. bul (x) : Sıralı kümede x i bulur. Kümede öyle bir en küçük y elemanı bul ki y x. Bu tür bir eleman yoksa null, varsa y döndür. Bu tarzdaki bul (x) işlemi bazen bir ardıl arama olarak adlandırılır. UKüme.bul(x) ten temel bir şekilde farklıdır, çünkü kümede x eşiti herhangi bir eleman olmasa bile anlamlı bir sonuç döndürür. UKüme ve SKüme bul (x) işlemleri arasındaki ayrım çok önemlidır ve çoğu kez cevapsızdır. Bir SKüme tarafından sağlanan ekstra işlevsellik genellikle hem daha büyük bir çalışma süresi ve hem de daha yüksek bir uygulama karmaşıklığını içeren bir eder ile birlikte gelir. Örneğin, bu kitapta tartışılan SKüme uygulamalarının çoğunda bul (x) işlemleri küme boyutu ile logaritmik bir çalışma süresine sahiptir. Öte yandan, Bölüm 5 teki gibi UKüme nin ZincirliKarımTablosu olarak uygulamasında sabit beklenen zamanda çalışan bir bul(x) işlemi vardır. Hangi yapıyı seçeceğinize karar verirken, SKüme tarafından sunulan ekstra işlevsellik gerçekten gerekli olmadıkça, her zaman bir UKüme kullanmalısınız. 15

16 1.3 Matematiksel Zemin Bu bölümde, biz, logaritma, büyük-oh gösterimi ve olasılık teorisi de dahil olmak üzere bu kitap boyunca kullanılan bazı matematiksel gösterimler ve araçları gözden geçireceğiz. Bu yorum kısa olacaktır ve bir giriş olarak tasarlanmamıştır. Birikimlerinin eksik olduğunu hisseden okuyucuları, bilgisayar bilimleri için matematik [50] konusunda yazılmış çok iyi (ve ücretsiz) ders kitabının uygun bölümlerini okumaları ve alıştırmalar yapmaları yönünde teşvik ediyoruz Üslüler ve Logaritmalar bx ifadesi b sayısının x üssüne yükseltilmiş halini gösterir. x pozitif bir tamsayıysa, bu sadece b değerinin x 1 defa kendisiyle çarpılmış haline eşittir: x negatif bir tam sayı olduğu zaman, bx = 1 / b-x. x = 0 iken, bx = 1. b tamsayı değilse, biz hala üssel fonksiyonu, üssel seri cinsinden tanımlanan ex (aşağıya bkz.) açısından tanımlayabiliriz, ama en iyisi bunu bir hesap analizi kitabına bırakalım. Bu kitapta, log b k ifadesi k nın taban-b logaritmasını ifade eder. Yani, tekil bir x değeri aşağıdaki koşulu sağlar. Bu kitaptaki logaritmaların çoğu taban 2 dir (ikili logaritmadır). Bunlar için, tabanı ihmal ederiz, böylece log 2 k için kısaltma olarak log k kullanılır. 16

17 Logaritmaları düşünmenin biçimsel, ama yararlı bir yolu da log b k için sonuç 1'e eşit ya da daha az olana dek k nın b ye kaç defa bölündüğünü bulmaktır. Örneğin, bir ikili arama yaptığımızda, her bir karşılaştırma, muhtemel cevapların sayısını 2 faktörü kadar azaltır. Olası en çok bir cevap kalana kadar bu tekrarlanır. Bu nedenle, başlangıçta en fazla n + 1 olası cevap olduğunda ikili arama tarafından yapılan karşılaştırma sayısı en fazla log 2 (n + 1) dir. Bu kitapta birkaç kez ortaya çıkan başka bir logaritma türü de doğal logaritmadır. Burada log e k belirtimi için ln k gösterimini kullanırız. e Euler sabiti olarak aşağıda verilmiştir: Doğal logaritma sık sık gündeme gelir, çünkü bu aşağıda verilen özellikle yaygın bir integralin değeridir: Logaritmalar ile en çok yaptığımız iki çalışmadan birincisi onları bir üsten kaldırmaktır: ve ikincisi logaritmanın tabanını değiştirmektir: Örneğin, doğal ve ikili logaritmayı karşılaştırmak için bu iki işlemi kullanabilirsiniz: 17

18 1.3.2 Faktöryeller Bu kitapta, bir ya da iki yerde, faktöryel fonksiyonu kullanılmıştır. Negatif olmayan bir n tamsayısı için, n! (okunuşu "n faktöryel") gösterimi şu anlamda tanımlanmıştır : Faktöryeller ortaya çıkmıştır çünkü n!, n farklı elemanın permütasyon sayısını; yani sıralamasını, sayar. Özel durum n = 0 için, 0! = 1 olarak tanımlanmaktadır. n! sayısı Stirling'in Yaklaşımı kullanılarak yaklaşık olarak tahmin edilebilir : Burada Stirling'in Yaklaşımı ln (n!) değerini de yaklaşık olarak tahmin eder. (Aslında, Stirling'in Yaklaşımı nın en kolay kanıtı ln (n!) = ln 1 + ln ln n ifadesinin değerini yaklaşık olarak integrali ile tahmin etmektir.) Faktöryel fonksiyonu ile ilgili olarak iki terimli katsayılara değineceğiz. Negatif olmayan bir tamsayı n ve bir tamsayı k {0,, n} için şu gösterim doğrudur: 18

19 İki terimli katsayı (okunuşu : n in k tercihi ) n elemanlı bir kümenin k elemanlı alt kümelerinin sayısını sayar; yani {1,, n} kümesinden k farklı tamsayıyı seçme yollarının sayısıdır Asimptotik Gösterim Bu kitapta veri yapılarını analiz ederken, çeşitli işlemlerin çalışma zamanları hakkında konuşmak istiyoruz. Tam kesinlikte çalışma zamanları, tabii ki, bilgisayardan bilgisayara ve hatta tek bir bilgisayar üzerinde çalıştırmadan çalıştırmaya değişecektir. Bir işlemin çalışma süresi hakkında konuştuğumuzda, işlem sırasında gerçekleştirilen bilgisayar komutları sayısına başvuruyoruz. Basit bir kod için bile, bu miktarı tam olarak hesaplamak zor olabilir. Bu nedenle, çalışma zamanlarını tam kesinlikte analiz etmek yerine biz, büyük-oh adı verilen notasyonu kullanacağız: Bir f (n) fonksiyonu için, O (f (n)) bir dizi fonksiyon gösterir; öyle ki; Grafiksel düşünüldüğünde, bu küme fonksiyonları g (n) fonksiyonlarından oluşur; burada c f(n), n yeterince büyük olduğunda, g (n) e başat olmaya başlar. Biz genellikle fonksiyonları kolaylaştırmak için asimptotik gösterimi kullanırız. Örneğin 5n log n + 8n 200 yerine O (n lg n) yazabiliriz. Bu şu şekilde kanıtlanmıştır : 19

20 Bu gösteriyor ki, 5n log n + 8n 200 fonksiyonu c = 13 ve n0 = 2 için O (n lg n) kümesindedir. Asimptotik notasyonu kullanırken bir dizi faydalı kısayollar uygulanabilir. Birincisi : herhangi bir c1 < c2 için. İkincisi: Herhangi a, b, c > 0, sabit olmak şartıyla, Bu kapsama bağıntıları herhangi bir pozitif değer ile çarpıldığında hala geçerli olur. Örneğin, n çarpıldığında şunu elde ederiz : Uzun ve seçkin bir geleneğin devamı olarak, biz bu notasyonu kötüye kullanarak gerçekten f1(n) O( f(n) ) demek istediğimizde f1(n) = O( f(n) ) yazacağız. Yine, bu işlemin yürütme süresi O( f (n) ) dir. gibi cümleler kuracağız. Gerçekte bu cümle bu işlemin yürütme süresi O( f (n) ) in bir üyesidir. olmalıdır. Bu kısayollar çoğunlukla asimptotik notasyonu daha kolay denklem dizeleri içinde kullanmamızı sağlar. Aşağıdaki gibi ifadeler yazarken, özellikle garip bir örnek ortaya çıkar : Yine, bu daha doğru bir şekilde şöyle yazılmalıdır: O (1) ifadesi başka bir konuyu da gündeme getiriyor. Bu ifadede hiçbir değişken bulunmadığından, hangi değişkenin rasgele büyük olduğu açık olmayabilir. Bağlam olmadan 20

21 bunu söylemenin hiçbir yolu yoktur. Yukarıdaki örnekte, denklemin geri kalanındaki tek değişken n olduğu için, denklemi şöyle okumamız gerektiğini varsayabiliriz : f(n) = 1 iken; T(n) = 2 log(n) + O (f(n)). Büyük-Oh notasyonu bilgisayar bilimleri için yeni ve benzersiz değildir. Sayı kuramcısı Paul Bachmann tarafından 1894 gibi erken bir tarihte kullanılmıştır, ve bilgisayar algoritmalarının yürütme zamanlarını açıklamak için son derece yararlıdır. Aşağıdaki kod parçasını düşünün: Bu yöntemin bir uygulaması şu işlemleri içerir : 1 atama (int i = 0), n + 1 karşılaştırma (i < n), n artırım (i ++), n bağıl konum dizi hesaplaması (a [i]), ve n dolaylı atama (a [i] = i). Bu yüzden bu yürütme zamanını şöyle yazabiliriz : Burada a, b, c, d ve e, kodu çalıştıran makineye bağlı olan sabitlerdir ve sırasıyla atamaları, karşılaştırmaları, artırım işlemlerini, bağıl konum dizi hesaplamalarını ve dolaylı atamaları gerçekleştirmek için gerekli zamanı simgelerler. Bu ifade iki satır kod çalışma süresini gösterirse de, açıkça bu tür bir analiz karmaşık kod veya algoritmalar için kolay işlenemeyecektir. Büyük-Oh notasyonunu kullanarak, çalışma süresi basitleştirilmiş halde şöyledir: 21

22 Bu sadece daha küçük boyutlu olmakla kalmaz, ama aynı zamanda yaklaşık olarak aynı bilgiyi vermektedir. Yukarıdaki örnekte yürütme süresinin a, b, c, d ve e sabitlerine bağlı olması, genel olarak, bu sabitlerin değerlerini bilmeden iki çalışma sürelerinden hangisinin daha hızlı olduğunu bilmek için karşılaştırmanın mümkün olamayacağı anlamına gelir. Bu sabitleri belirlemek için (diyelim ki, zamanlama testleri aracılığıyla) çaba göstersek bile, sonuç sadece bizim üzerinde test yaptığımız makine için geçerli olacaktır. Büyük-Oh notasyonu bizim daha karmaşık fonksiyonları çözümlememizi sağlayarak, çok daha yüksek düzeyde akıl ve mantık yürütmemize ve düşünmemize olanak verir. İki algoritmanın aynı büyük-oh çalışma süresi varsa, hangisinin daha hızlı olduğunu bilemezsiniz, ve net bir kazanan olmayabilir. Biri tek makinede daha hızlı olabilir, ve diğeri farklı bir makinede daha hızlı olabilir. Ancak, iki algoritmanın kanıtlanabilir farklı büyük-oh çalışma süreleri varsa, o zaman emin olabiliriz ki daha küçük çalışma süresi olan yeterince büyük n değerleri için daha hızlı olacaktır. Büyük-Oh notasyonu bize, iki farklı fonksiyonu karşılaştırmak için olanak tanır. Buna örnek, f1(n) = 15n ve f2(n) = 2n logn fonksiyonlarının büyüme hızlarını karşılaştıran Şekil 1.5 'te gösterilmiştir. Burada f1 (n) karmaşık bir oğrusal zaman algoritmasının yürütme zamanı olabilecekken, f2 (n) böl-ve-yönet paradigmasına dayanan oldukça daha basit bir algoritmanın çalışma zamanı olabilir. Bu göstermektedir ki, f1 (n) küçük n değerleri için f2 (n)'den daha büyük olmasına rağmen, büyük n değerleri için karşıtı geçerlidir. Sonunda f1 (n) giderek artan farkla kazanır. Büyük-Oh gösterimi kullanılarak yapılan analiz bunun böyle olacağını bize anlatmıştı, çünkü O (n) O (n log n). Birkaç durumda, birden fazla değişkenli fonksiyonlar üzerinde de asimptotik gösterimi kullanacağız. Bunun için herhangi bir standart yoktur, ama bizim amaçlarımız için, aşağıdaki tanım yeterlidir: 22

23 Bu tanım, bizim gerçekten önem verdiğimiz durumu yakalar: n1,, nk argümanlarının g nin büyük değer almasını sağlaması. Bu tanım, aynı zamanda tek değişkenli O(f (n) tanımı ile, f (n) n in artan bir fonksiyonu olduğu zaman uzlaşır. Bizim amaçlarımız için bu kadarının yeterli olmasına rağmen okuyucu, diğer metinlerde çok değişkenli fonksiyonlar ve farklı asimptotik gösterimlerin de ele alınabileceği konusunda uyarılmalıdır. 23

24 1.3.4 Rasgele Sıralama ve Olasılık Bu kitapta sunulan veri yapılarının bazıları rasgeleleştirilmiştir, depolanan verilerden veya onların üzerinde yapılan işlemlerden bağımsız rasgele seçimler yaparlar. Bu nedenle, bu gibi yapılar kullanılarak aynı işlem setinin bir kereden fazla çalıştırılması farklı yürütme zamanlarına neden olabilir. Bu veri yapılarını analiz ederken, onların ortalama veya beklenen çalışma süreleri ile ilgileniriz. Kurallı olarak, bir rasgele veri yapısı üzerindeki bir işlemin çalışma süresi rasgele bir değişkendir, ve biz onun beklenen değerini incelemek istiyoruz. Değerlerini bazı sayılabilir U evreninden alan bir süreksiz rasgele değişken X için, E [X] ile gösterilen, X in beklenen değeri, aşağıdaki formül ile verilmektedir : Burada Pr {ε} olay ε nin meydana gelme olasılığını gösterir. Bu kitaptaki tüm örneklerde, bu olasılıklar yalnızca rasgeleleştirilmiş veri yapısı tarafından yapılan rasgele seçimler hakkındadır; ne veri yapısında depolanan verinin, ne de veri yapısı üzerinde gerçekleştirilen işlemlerin sırasının, rasgele olduğuna dair bir varsayım yoktur. Beklenen değerlerin en önemli özelliklerinden biri, beklenti doğrusallığıdır. Herhangi iki rasgele değişken X ve Y, için Daha genel olarak, herhangi rasgele değişkenler X1,, Xk, için 24

25 Beklentinin doğrusallığı karmaşık rasgele değişkenleri (yukarıdaki denklemlerin sol tarafındakiler gibi) basit rasgele değişkenlerin toplamları halinde (sağ taraflar) bölmemiz için bize olanak tanır. Tekrar tekrar kullanacağımız yararlı bir hile, gösterge rasgele değişkenlerini tanımlamaktır. Bu ikili değişkenler bir şeyi saymak istediğimizde yararlıdır ve en iyi bir örnekle açıklanır. Adil bir bozuk parayı k kere fırlattığımızı varsayalım, para yere düşünce kaç kez tura gelmesinin beklenen sayısını bilmek istiyorum. Sezgisel olarak, cevabın k/2 olduğunu biliyoruz, ama eğer beklenen değer tanımını kullanarak bunu kanıtlamak için çalışırsak, Burada hesaplamayı ve ve ikili özdeşliklerini yeterince bilmemiz gereklidir. Gösterge değişkenlerini ve beklenti doğrusallığını kullanarak işler çok daha kolay hale gelir. Her i {1,, k} için, gösterge rasgele değişkeni tanımlayalım : O zaman 25

26 Şimdi,, bu yüzden Bu, biraz daha uzun solukludur, ama bizim herhangi bir sihirli özdeşlik bilmemizi veya herhangi bir önemsiz olmayan olasılık hesaplamamızı gerektirmiyor. Daha da iyisi, paraların tam olarak yarısının tura geleceği sezgisi ile uyumludur., çünkü her para 1/2 olasılık ile tura olarak ortaya çıkıyor. 1.4 Hesaplama Modeli Bu kitapta, biz çalıştığımız veri yapıları üzerindeki işlemlerin teorik çalışma sürelerini analiz edeceğiz. Tam olarak bunu yapmak için, bir matematiksel hesaplama modeli gereklidir. Bunun için, biz w-bit sözcük-ram modelini kullanacağız. RAM Rasgele Erişimli Makine ye denk gelir. Bu modelde, her biri bir w-bit sözcük depolayan hücrelerden oluşan bir rasgele erişimli belleğe erişimimiz vardır. Bu demektir ki bir bellek hücresi, örneğin, {0,, 2w 1} kümesinden bir tamsayıyı simgeleyebilir. Sözcük-RAM modelinde, sözcükler üzerindeki temel işlemler sabit zaman alır. Bu aritmetik işlemleri (+,,, /, %), karşılaştırmaları (<, >, =,, ), ve bit-bit-boole işlemleri içerir (bitbit-ve, VEYA, ve dışlayıcı-veya). Herhangi bir hücre sabit zamanda okunabilir veya yazılabilir. Bir bilgisayarın belleği istediğimiz herhangi büyüklükte bir bellek bloğunun tahsis edilmesini veya serbest bırakılmasını sağlayacak bir bellek yönetim sistemi tarafından yönetilmektedir. k boyutunda 26

27 bir bellek bloğunu tahsis etmek O (k) zaman alır ve yeni ayrılan bellek bloğu için bir işaretçi döndürür. Bu işaretçi, bir tek sözcük ile temsil edilebilecek kadar küçüktür. Sözcük-boyutu, w, bu modelin çok önemli bir parametresidir. w hakkında yapılacak tek varsayım alt sınır w log n, burada n herhangi bir veri yapımızda saklanan elemanların sayısıdır. Bu oldukça orta halli bir varsayımdır, aksi takdirde bir veri yapısında saklanan elemanların sayısını saymak için bile sözcük yeterince büyük olmayacaktır. Alan sözcüklerle ölçülür, o yüzden bir veri yapısı tarafından kullanılan alan miktarından bahsederken, yapı tarafından kullanılan bellek sözcük sayısı ile ilgileniyoruz. Veri yapılarımızın tümü, bir genel tür olan T değerlerini saklar, ve T türü bir elemanın belleğin bir sözcüğünü kapladığını varsayarız. (Gerçekte, biz T türü nesnelere başvuruları depoluyoruz, ve bu referanslar bellekte sadece bir sözcük işgal ediyor.) w-bit sözcük-ram modeli (32-bit) Java Sanal Makinesi (JVM) ile, w = 32 olduğunda, oldukça yakın uyuşur. Bu kitapta sunulan veri yapıları JVM ve çoğu diğer mimariler üzerinde uygulanabilir olmayan özel hileler kullanmaz. 1.5 Doğruluk, Zaman Karmaşıklığı ve Alan Karmaşıklığı Bir veri yapısının performansını incelerken, en önemli üç şey vardır : Doğruluk: Veri yapısı doğru şekilde arayüzünü uygulamalıdır. Zaman karmaşıklığı: Veri yapısı üzerindeki işlemlerin çalışma süreleri mümkün olduğunca küçük olmalıdır. Alan karmaşıklığı: Veri yapısı mümkün olduğunca az bellek kullanmalıdır. Bu giriş bölümünde, doğruluğu bize verilmiş olarak varsayacağız; sorgulara hatalı yanıtlar veren veya düzgün güncelleme yapmayan veri yapılarını dikkate almayacağız. Ancak, en az alan kullanımını çalıştırmak için ekstra bir çaba gösteren veri yapılarını göreceksiniz. Bu 27

28 genellikle işlemlerin (asimptotik) yürütme sürelerini etkilemez, ama pratikte veri yapılarını biraz daha yavaş yapabilir. Çalışma sürelerini veri yapıları bağlamında incelerken, üç farklı tür çalışma süresi garantisi eğilimi ile karşılaşırız: En-kötü durum çalışma süresi : Bunlar çalışma süresi garantilerinin en güçlü türüdür. Bir veri yapısı işlemi f (n) en-kötü durum çalışma süresine sahipse, o zaman her bir işlemin çalışma süresi f (n) den daha uzun zaman asla almaz. Amortize çalışma süresi : Bir veri yapısı içinde bir işlemin amortize çalışma süresinin f (n) olduğunu söylemek ise o zaman bu, tipik bir işlemin maliyetinin en fazla f (n) olduğu anlamına gelir. Daha kesin olarak, bir veri yapısı f (n) amortize çalışma süresine sahipse, bir dizi m işlemleri en fazla m f (n) zamanda çalışır. Bazı işlemler bireysel olarak f (n) den daha fazla sürebilir, ancak işlemlerin bütün dizisi için, ortalama, en fazla f (n) dir. Beklenen çalışma süresi: Bir veri yapısı üzerinde bir işlemin beklenen çalışma süresinin f (n) olduğunu söylediğimizde, bu gerçek çalışma süresinin bir rasgele değişken (bkz. Bölüm 1.3.4) olduğu ve bu rasgele değişkenin beklenen değerinin en fazla f (n) olduğu anlamına gelir. Buradaki rasgelelik veri yapısı tarafından yapılan rasgele seçimler ile ilgilidir. En-kötü durum, amortize ve beklenen çalışma zamanları arasındaki farkı anlamak için bir mali örneği düşünmek yardımcı olur. Bir ev satın alma maliyetini düşünün: En-kötü durum a karşılık amortize maliyet : Bir ev maliyetinin 120,000 $ olduğunu varsayalım. Bu evi satın almak için, 1,200 $ aylık ödemeler ile 120 aylık (10 yıl) ipotek alabiliriz. Bu durumda, bu ipoteğin ödeme maliyeti en-kötü durumda aylık 1,200 $ olur. Elimizde yeterli para varsa, 120, 000 $ bir ödeme ile evi doğrudan satın almayı seçebiliriz. Bu durumda, 10 yıllık bir süre içinde, bu evi satın almanın amortize edilmiş aylık maliyeti 28

29 120,000 $ / 120 ay = 1,000 $ aylık. Bu, eğer ipoteği eğer ödemek zorunda kalsaydık ayda 1,200 $ dan daha azdır. En-kötü durum a karşılık beklenen maliyet : Şimdi, bizim 120,000 $ lık evimizde, yangın sigortası sorununu dikkate alalım. Yüzbinlerce olayı inceleyen sigorta şirketleri, bizimki gibi bir evde beklenen aylık yangın hasar miktarının 10 $ olduğunu belirlediler. Bu çok küçük bir sayıdır, çünkü pek çok evde asla yangın çıkmaz, birkaç evde biraz duman hasarı yaratan bazı küçük yangınlar olabilir, ve evlerin pek azı büyük yangın geçirir. Bu bilgilere dayanarak, sigorta şirketi yangın sigortası için 15 $ aylık ücret talep eder. Şimdi karar zamanı. Yangın sigortası için en-kötü durumda 15 $ aylık maliyeti ödemeli miyiz, ya da risk alıp ayda 10 $ beklenen maliyet pahasına kendi kendimizi sigortalamamız mı gerekir? Açıkçası, beklentide aylık 10 $ daha az masraf yapıyor, ama biz gerçek maliyetin çok daha yüksek olabileceği olasılığını kabul etmek zorundayız. Bütün evin yanması olası durumunda, gerçek maliyet 120,000 $ olacaktır. Bu finansal örnekler neden bazen en-kötü durumda çalışan zaman yerine amortize edilmiş veya beklenen çalışma süresi ile yetindiğimize dair bize ışık tutuyor. Çoğunlukla en-kötü zamandan daha düşük bir beklenen veya amortize zaman elde etmek mümkündür. En azından, amortize veya beklenen çalışma süreleriyle yetinmeye istekli bir kimsenin çok daha basit bir veri yapısı elde etmesi sıklıkla mümkündür. 1.6 Kod Örnekleri Bu kitaptaki kod örnekleri Java programlama dilinde yazılmıştır. Ancak Java'nın yapıları ve anahtar kelimelerinin tümüne aşina olmayan okuyuculara kitabı erişilebilir hale getirmek için, kod örnekleri basitleştirilmiştir. Örneğin, bir okuyucu public, protected, private veya static gibi anahtar kelimelerden hiçbirini bulamayacaktır. Okuyucu aynı zamanda sınıf hiyerarşileri hakkında da fazla tartışma bulamayacaktır. Belirli bir sınıfın hangi arayüzleri uyguladığı, veya hangi sınıfı genişlettiği, eğer tartışma ile ilgiliyse, ilişikteki metinden açık olmalıdır. Böylece, 29

30 B, C, C + +, C #, Objective-C, D, Java, JavaScript, dahil ALGOL geleneğinden gelen herhangi bir dilin birikimine sahip olan herkes tarafından kod örnekleri anlaşılabilir hale gelmiştir. Tüm uygulamaların bütün ayrıntılarını isteyen okuyucular bu kitaba eşlik eden Java kaynak koduna bakabilirler. Bu kitapta çalışma zamanlarının matematiksel analizleri ile analiz edilen algoritmalar için Java kaynak kodunu karışık halde bulacaksınız. Bunun anlamı, bazı denklemler kaynak kodunda da bulunan değişkenleri içerir. Bu değişkenler hem kaynak kodu içinde ve hem de denklem içinde sürekli dizilirler. Bu tür değişkenlerin en yaygını, istisnasız olarak, her zaman veri yapısında depolanan eleman sayısına karşılık gelen n dir. 1.7 Veri Yapıları Listesi Tablo 1.1 ve 1.2 Bölüm 1.2 'de anlatılan Liste, UKüme ve SKüme arayüzlerini bu kitapta gerçekleştiren veri yapılarının performansını özetliyor. 30

31 1.8 Tartışma ve Alıştırmalar Bölüm 1.2 de açıklanan Liste, UKüme ve SKüme arayüzleri Java Koleksiyonları Çerçevesi [54] tarafından etkilenmektedir. Bunlar Java Koleksiyonlar Çerçevesinde bulunan List, Set, Map, SortedSet ve SortedMap arayüzlerinin esas olarak basitleştirilmiş versiyonlarıdır. İlişikteki kaynak kod, Set, Map, SortedSet ve SortedMap uygulamaları içine UKüme ve SKüme uygulamalarını gerçekleştirmek için gerekli sarmalayan sınıfları içerir. Bu bölümde tartışılan matematik, asimptotik gösterim, logaritma, faktöriyel, Stirling yaklaşımı, temel olasılık ve daha fazlası dahil olmak üzere mükemmel (ve serbest) bir şekilde Leyman, Leighton, ve Meyer [50] tarafından ele alınmıştır. Üssel ve logaritmaların biçimsel tanımlarını içeren ılımlı bir hesap kitabı için ise, Thompson [73] tarafından kaleme alınmış (serbestçe kullanılabilir) klasik kitaba başvurunuz. 31

32 Özellikle bilgisayar bilimleri ile ilgili olarak temel olasılık hakkında daha fazla bilgi için, Ross [65] tarafından yazılmış ders kitabına bakmanız önerilir. Asimptotik gösterim ve olasılığı kapsayan başka bir iyi referans da, Graham, Knuth ve Patashnik tarafından yazılan ders kitabıdır [37]. Kendi Java programlamalarını tazelemek isteyen okuyucular etkileşimli pek çok Java eğitimlerini bulabilirler [56]. Alıştırma 1.1. Bu egzersiz doğru problem için doğru veri yapısı seçimini okuyucuya tanıtmaya yardımcı olmak için tasarlanmıştır. Gerçekleştirilirse, bu alıştırmanın bölümleri Java Koleksiyonları Çerçevesi tarafından sağlanan ilgili arayüzün (Yığıt, Kuyruk, İki Başlı Kuyruk, UKüme veya SKüme) bir uygulamasından yararlanarak yapılmalıdır. Aşağıdaki problemleri bir metin dosyasını her seferde bir satır okuyarak ve her satır için işlemleri uygun veri yapısı (ları) içinde gerçekleştirerek çözün. Uygulamalarınız, bir milyon satır içeren dosyaları bile birkaç saniye içinde işlenebilecek şekilde yeterince hızlı olmalıdır. 1. Girdiyi bir seferde bir satır olmak üzere okuyun ve daha sonra ters sırayla satırları yazın. Son giriş satırı ilk olarak yazılacaktır; daha sonra sondan ikinci giriş satırı yazılacaktır, ve benzeri. 2. Girdinin ilk 50 satırını okuyun ve daha sonra bunları ters sırayla yazın. Sonraki 50 satırı okuyun ve daha sonra ters sırayla bunları yazın. Bunu okumak için artık satır kalmayana dek devam ettirin. Bu noktada kalan satırlar tersten çıktıya yazılmalıdır. Diğer bir deyişle, çıktınız ilk satırda 50. satır, sonra 49.satır, sonra 48.satır ile başlayacak ve bu böyle 1.satıra kadar devam edecektir. Bunu takiben, 100.satır, sonra 99.satır yazılacak ve bu böyle 51.satıra kadar devam edecektir. Ve benzeri. Kodunuz herhangi bir zamanda asla 50 satırdan fazla saklamak zorunda değildir. 3. Her seferde bir girdi satırı okuyun. İlk 42 satırı okuduktan sonra herhangi bir noktada, eğer bazı satırlar boşsa (yani, 0 uzunluğunda bir dize) ondan 42 satır öncesindeki satırı çıktı olarak yazın. Örneğin 242.satır boş ise, programın çıktısı 200.satır olmalıdır. Bu 32

33 program herhangi bir zamanda, 43 satırdan fazla girdi depolamayacak şekilde gerçekleştirilmelidir. 4. Her seferde bir girdi satırı okuyun ve her satırı, önceki giriş satırlarında yinelenmediyse çıktıya yazın. Çok fazla yinelenen satır içeren bir dosyanın tekil satır sayısı için gerekli olandan daha fazla bellek kullanmaması gerektiğine özellikle dikkat edin. 5. Her seferde bir girdi satırı okuyun ve bu satırı daha önce zaten okuduysanız çıktıya yazın. (Sonuçta, her satır ilk geçtiği yerden silinecektir.) Çok fazla yinelenen satır içeren bir dosyanın tekil satır sayısı için gerekli olandan daha fazla bellek kullanmaması gerektiğine özellikle dikkat edin. 6. Tüm girdiyi her seferde bir satır olacak şekilde okuyun. Sonra uzunluğuna göre sıralanmış tüm satırları, kısa satırlar önce olmak üzere, çıktıya yazın. İki satırın aynı uzunluğa sahip olması durumunda, her zamanki sıralama ölçütünü kullanarak sıralarını çözümleyiniz. Yinelenen satırlar sadece bir kez yazılmalıdır. 7. Önceki soruda istenenin aynısını yapın, yalnız bu sefer yinelenen satırlar girdide göründükleri satır sayısı kadar çıktıda yazılmış olmalıdır. 8. Her seferde bir girdi satırı okuyun ve çift sayılı satırları (0.satır ile başlayan ilk satır ile) çıktıya yazın; daha sonra tek sayılı satırları yazın. 9. Tüm girdiyi her seferde bir satır olacak şekilde okuyun ve satırları çıktıya yazmadan önce rasgele permütasyon yapın. Açık olmak gerekirse: Herhangi bir satırın içeriğini değiştirmemeniz gerekir. Bunun yerine, aynı satır topluluğu yazdırılır, ama rasgele sırayla yapılmalıdır. Alıştırma 1.2. Bir Dyck sözcüğü +1 ve 1 lerden oluşur ve dizinin herhangi bir önek toplamının negatif olmaması şartı aranır. Örneğin +1, 1, +1, 1 bir Dyck sözcüğüdür, ancak +1, 1, 1, +1 değildir, çünkü önek < 0. Dyck sözcüğü ve Yığıt yığ (x) ve sil () işlemleri arasındaki herhangi bir ilişkiyi açıklayın. 33

34 Alıştırma 1.3. Bir uyumlu dize düzgün eşleştirilen bir {, }, (, ), [, ] karakter dizisidir. Örneğin, {{()[]}} bir uyumlu dizedir, ancak {{()]} değildir, çünkü ikinci { eşleşmesi ] olmuştur. n uzunluğunda bir dize verildiğinde, bunun bir uyumlu dize olup olmadığını belirlemek için O(n) zamanında çalışan bir yığıtın nasıl kullanılacağını gösterin. Alıştırma 1.4. Sadece yığ (x) ve sil () işlemlerini destekleyen bir Yığıt, s, olduğunu varsayalım. Sadece bir FIFO Kuyruk, q, kullanarak nasıl tüm elemanların sırasını tersine çevirebileceğinizi gösterin. Alıştırma 1.5. Bir UKüme kullanarak, Torba uygulayınız. Bir Torba UKüme gibidir ekle(x), sil(x) ve bul(x) yöntemlerini destekler ama yinelenen elemanların saklanmasını da sağlar. Bir Torba daki bul (x) işlemi herhangi x elemanı (varsa) döndürür. Buna ek olarak, Torba x e eşit olan tüm elemanların bir listesini döndüren hepsinibul (x) işlemini destekler. Alıştırma 1.6. Liste, UKüme ve SKüme arayüzlerinin uygulamalarını sıfırdan yazınız ve test ediniz. Bunların verimli olması gerekmez. Daha verimli uygulamalarının doğruluğunu ve performansını test etmek için daha sonra kullanılabilir. (Bunu yapmanın en kolay yolu, elemanları bir dizide depolamaktır.) Alıştırma 1.7. Önceki soruda yaptığınız uygulamalarınızın performansını artırmak için aklınıza gelebilecek herhangi bir hileyi kullanarak çalışın. Liste uygulamasında ekle (i, x) ve sil (i) yöntemlerinin performansını nasıl artıracağınızı düşünün ve deney yapın. UKüme ve SKüme uygulamalarında bul (x) işleminin performansını nasıl artıracağınızı düşünün. Bu alıştırma size bu arayüzlerin etkili uygulamalarını elde etmenin ne kadar zor olabileceğine dair bir fikir vermek için tasarlanmıştır. 34

35 Bölüm 2 Dizi-Tabanlı Listeler Bu bölümde, Liste ve Kuyruk arayüzlerinin destek dizi denilen bir dizide temel verinin depolandığı uygulamalarını çalışacağız. Aşağıdaki tablo, bu bölümde sunulan veri yapıları için işlemlerin çalışma sürelerini özetliyor. Tek bir diziye veri depolayarak çalışan veri yapılarının ortak birçok avantaj ve sınırlamaları vardır : Diziler dizideki herhangi bir değere sabit zamanlı erişimi sunuyor. Bu, al(i) ve belirle(i, x) işlemlerinin sabit zamanda çalışmasını sağlıyor. Diziler çok dinamik değildir. Listenin ortasına yakın bir elemanın eklenmesi veya kaldırılması dizideki çok sayıda elemanın yeni eklenen elemana yer açmak için veya silinen eleman tarafından yaratılan boşluğu doldurmak için kaydırılmış olmasını gerektirir. Bu nedenle ekle (i, x) ve sil (i) işlemlerinin çalışma süreleri n ve i ye bağlıdır. Diziler genişlemez veya küçülmezler. Veri yapısındaki elemanların sayısı destek dizinin boyutunu aşarsa yeni bir dizinin tahsis edilmesi ve eski diziden verilerin yeni diziye kopyalanması gerekir. Bu pahalı bir işlemdir. Üçüncü nokta önemlidir. Yukarıdaki tabloda belirtilen çalışma süreleri büyüyen ve küçülen destek dizi ile ilişkili maliyeti dahil etmemektedir. Göreceksiniz ki, eğer dikkatli bir şekilde yönetilirse, destek diziyi büyültüp ve küçültmenin maliyeti ortalama bir işlemin maliyetine fazla bir yük getirmemektedir. Daha doğrusu, boş bir veri yapısı ile başlayarak herhangi bir sırada m adet ekle (i, x) ve sil (i) işlemini yürütürsek, destek diziyi büyültüp ve küçültmenin 35

36 tüm bu m işlem serisi üzerindeki maliyeti O(m) olur. Bazı bireysel işlemler daha pahalı olmasına rağmen tüm m adet işlem üzerinden amortize maliyet, her işlem için sadece O(1) 'dir. 2.1 Dizi Yığıtı: Dizi Kullanan Hızlı Yığıt İşlemleri Bir Dizi Yığıtı destek dizi denilen bir a dizisini kullanarak liste arayüzünü gerçekleştirir. i konumunda bulunan liste elemanı, a[i] içinde depolanır. Çoğu zaman, a, tam olarak gerekli olduğundan daha büyük olabilir, bu nedenle gerçekte a dizisinde saklanan elemanların sayısını tutmak için bir n tamsayısı kullanılır. Bu şekilde, listenin elemanları a[0],, a[n-1] içine depolanır, ve her zaman a.boyut n olur Temel Bilgiler al(i) ve belirle(i, x) işlemlerini kullanarak Dizi Yığıtı elemanlarına erişmek ve onları değiştirmek kolaydır. Gerekli sınır denetimini yaptıktan sonra geriye sadece, sırasıyla, a[i] değeri döndürmek veya değiştirmek kalır. 36

37 Dizi Yığıtı na eleman ekleme ve kaldırma işlemleri Şekil 2.1 de örneklenmiştir. ekle(i,x) işlemini gerçekleştirmek için ilk olarak a dizisinin halen dolu olup olmadığını kontrol ediyoruz. Eğer öyleyse, a nın boyutunu artırmak için yeniden_boyutlandır () yöntemini çağırıyoruz. yeniden_boyutlandır () işleminin nasıl gerçekleştirildiği daha sonra ele alınacaktır. Şimdilik, şu kadarını bilmek bize yeter, bir yeniden_boyutlandır () çağrısından sonra, emin olabiliriz ki a.boyut > n olur. Bunu tamamlayıp hallettikten sonra şimdi x e yer açmak için a[i],,a[n 1] elemanlarını bir konum sağa kaydırıyoruz, sonra a[i] elemanını x değerine eşitliyoruz ve n değerini 1 artırıyoruz. yeniden boyutlandır() çağrısının potansiyel maliyetini göz ardı edersek, ekle(i, x) işleminin maliyeti x e yer açmak için kaydırmamız gereken elemanların sayısı ile orantılıdır. Bu nedenle, bu işlemin maliyeti (boyutlandırma maliyeti görmezden gelinerek) O(n i+1) olur. sil (i) işlemini uygulamak da benzer şekildedir. a[i + 1],,a[n 1] elemanlarını bir konum sola kaydırıyoruz (a [i] üzerine yazarak), ve n değerini 1 azaltıyoruz. Bunu yaptıktan sonra a.length 3n koşulunu test ederek n değerinin a.length ten azımsanmayacak kadar çok küçük olup olmadığını kontrol ediyoruz. Koşul doğruysa, o zaman a nın boyutunu azaltmak için yeniden_boyutlandır () işlemini çağırıyoruz. 37

38 yeniden_boyutlandır() yönteminin maliyetini göz ardı edersek, bir sil (i) işleminin maliyeti kaydırdığımız elemanların sayısı ile orantılıdır, yani O(n i) ile ölçülür Büyültme ve Küçültme yeniden_boyutlandır() yöntemi oldukça basittir; boyutu 2n olan yeni bir b dizisi tahsis eder ve b nin ilk n pozisyonuna n elemanı kopyalar ve daha sonra a yı b ye belirler. Böylece bir yeniden_boyutlandır() çağrısından sonra a.length = 2n olur. 38

39 yeniden_boyutlandır() yönteminin gerçek maliyetini analiz etmek kolaydır. 2n boyutlu bir b dizisi tahsis eder ve n elemanı b içine kopyalar. Bu O(n) zaman alır. Önceki bölümde yaptığımız çalışma süresi analizi yeniden boyutlandırmak için yapılan çağrıların maliyetini göz ardı etmişti. Bu bölümde amortize analiz olarak bilinen bir teknik kullanarak bu maliyeti analiz edeceğiz. Bu teknik her ekle(i, x) ve sil (i) işlemi sırasında gerçekleştirilen yeniden boyutlandırma maliyetini belirlemeyi denemiyor. Bunun yerine, ekle(i, x) ve sil (i) işlemlerinin m defa çağrılması sırasında yeniden boyutlandırmak için yapılan tüm çağrıların maliyetini düşünüyor. Özellikle, şunu göstereceğiz : Öneri 2.1: Boş bir Dizi Liste oluşturulursa ve ekle(i, x) ve sil (i) işlemleri seri olarak m 1 kere çağrılırsa, o zaman yeniden_boyutlandır () için yapılan tüm çağrılar sırasında harcanan toplam zaman O(m) olur. Kanıt: yeniden_boyutlandır () her çağrıldığında yeniden_boyutlandır () için yapılan son çağrıdan bu yana ekle veya sil için yapılan çağrı sayısının en az n/2 1 olduğunu göstereceğiz. Bu nedenle, yeniden_boyutlandır () için yapılan i'inci çağrı sırasındaki n değeri ni ile temsil edilirse ve yeniden_boyutlandır () için yapılan çağrıların toplam sayısı r ile gösteriliyorsa, o zaman ekle(i, x) ya da sil (i) için yapılan toplam çağrı sayısı en az 39

40 bu da şuna eşittir, Öte yandan, yeniden_boyutlandır () için yapılan tüm aramalar sırasında harcanan toplam zaman, r değeri m den fazla olmadığından, Geriye yeniden_boyutlandır () için yapılan (i-1) inci ve i inci aramalar aralığında ekle (i, x) ya da sil (i) için yapılan çağrı sayısının en az ni / 2 olduğunu göstermek kalıyor. Dikkate alınması gereken iki durum vardır. İlk durumda, destek dizisi a dolu olduğundan ekle (i, x) tarafından yeniden_boyutlandır () çağrılıyor, yani, a.length = n = ni. Yeniden boyutlandırmak için yapılan bir önceki çağrıyı düşünün: Bir önceki bu çağrıdan sonra, a nın uzunluğu a.length ve depolanmış elemanların sayısı en fazla a.length/2 = ni /2 olur. Fakat şimdi a içinde depolanmış elemanların sayısı ni = a.length, yani bir önceki yeniden_boyutlandır () çağrısından bu yana ekle (i, x) için en azından ni/2 çağrı yapılmıştır. İkinci durum yeniden_boyutlandır (), sil (i) tarafından çağrıldığında oluşur çünkü a.length 3n = 3ni. Yine, yeniden boyutlandırmak için yapılan bir önceki çağrıdan sonra a içinde depolanmış elemanların sayısı en az a.length/2 1 olur.3 Şimdi a içinde depolanmış ni a.length/3 adet eleman vardır. Bu nedenle, yeniden boyutlandırmak için yapılan en son çağrıdan bu yana sil (i) işlemlerinin sayısı en az 3 Bu formüldeki 1, n = 0 ve a.length = 1 iken oluşan özel durum için hesaplanmıştır. 40

41 Her iki durumda da, kanıtı tamamlamak için gerekli olduğu gibi, yeniden_boyutlandır () için yapılan (i-1) inci ve i inci aramalar aralığında ekle (i, x) ya da sil (i) için yapılan çağrı sayısı en az ni / 2 1 olmuştur Özet Aşağıdaki teorem Dizi Yığıt ının performansını özetliyor : Teorem 2.1. Bir Dizi Yığıt, Liste arayüzünü uygular. yeniden_boyutlandır () için yapılan çağrıların maliyeti dikkate alınmayarak, Dizi Yığıt şu işlemleri destekler : al(i) ekle (i, x) ve belirle(i, x) işlem başına O(1) zamanı vardır; ve sil (i) işlem başına O(1+n i) zamanı vardır. Bundan başka, boş bir Dizi Yığıt oluşturulursa ve ekle(i, x) ve sil (i) işlemleri m 1 defa çağrılırsa, yeniden_boyutlandır () çağrıları için gerekli toplam çalışma süresi O(m) olur. Dizi Yığıt bir Yığıt uygulamanın etkili bir yoludur. Özellikle, yığ(x) yöntemini ekle(n, x) ile ve sil(x) yöntemini sil(n 1) ile gerçekleştirebiliriz. Bu işlemler O(1) amortize zamanda çalışır. 2.2 Hızlı Dizi Yığıtı: Optimize Dizi Yığıtı Bir Dizi Yığıtı tarafından yapılan çalışmaların çoğu veri kaydırma yı (ekle(n, x) ve sil(x) tarafından) ve kopyalamayı (yeniden_boyutlandır () tarafından) içerir. Yukarıda gösterilen uygulamalarda, for döngüleri kullanarak bunu gerçekleştirdik. Oysa ki, birçok programlama ortamlarının veri bloklarını kopyalama ve taşıma konusunda çok verimli olan özel işlevlere sahip olduğu ortaya çıkmıştır. C programlama dilinde memcpy(d,s,n) ve memmove(d,s,n) fonksiyonları vardır. C++ içinde std :: copy(a0, a1, b) ve algoritması vardır. Java da System:arraycopy (s, i, d, j, n) vardır. 41

42 Bu fonksiyonlar genellikle oldukça optimize edilmiştir ve hatta for döngüsü kullanarak yapabileceğimiz kopyalamadan çok daha hızlı özel makine komutları kullanırlar. Bu işlevleri kullanarak asimptotik çalışma saatlerini azaltmak mümkün olmasa da hala değerli birer optimizasyon olabilir. Buradaki Java uygulamalarında, sisteme özgü System.arraycopy(s,i,d,j,n) kullanımı, yapılan işlemlerin tiplerine bağlı olarak 2 ve 3 faktör arasında bir hız artışı ile sonuçlanmıştır. Sizin kilometre hızınız değişebilir. 2.3 Dizi Kuyruğu : Dizi-Tabanlı Kuyruk Bu bölümde, bir FIFO (ilk-giren-ilk-çıkar) kuyruğunu uygulayan Dizi Kuyruğu veri yapısını sunuyoruz, elemanlar eklendikleri (ekle () işlemi ile) sırayla aynı sırada kaldırılır (sil () işlemi ile). Bir Dizi Kuyruğu nun bir FIFO kuyruğunu uygulamak için kötü bir seçim olduğuna dikkat edin. İyi bir seçim değildir, çünkü elemanları bunun üzerine eklemek için önce listenin bir ucunu seçmeliyiz ve daha sonra diğer ucundan elemanları kaldırmalıyız. İki işlemden birinin listenin başında çalışması gereklidir, ki burada i = 0 değerindeyken ekle (x, i) ya da sil (i) çağrıları yapılsın. Bu n orantılı çalışma süresi demektir. 42

43 Verimli bir dizi-tabanlı uygulamayı edinmek için öncelikle bir sonsuz dizi a olsaydı sorunun kolay olacağını fark etmeliyiz. Kaldırılacak bir sonraki elemanın konumunu tutan bir j endeksi ve kuyruktaki eleman sayısını sayan bir tamsayı n tutardık. Kuyruk elemanları her zaman için şöyle saklanacaktır : Başlangıçta, j ve n ikisi de 0'a ayarlanmış olacaktır. Bir elemanı eklemek için a[j + n] konumuna yerleştiririz ve n değerini 1 artırırız. Bir elemanı kaldırmak için, a[j] konumundan onu sileriz, j değerini 1 artırırız ve n değerini 1 azaltırız. Tabii ki, bu çözümdeki sorun, sonsuz bir dizi gerektirmesidir. Bir Dizi Yığıtı sonlu bir dizi a ve modüler aritmetik kullanarak bu çözüm yoluna benzetim yapar. Bu, günün zamanı hakkında konuşurken kullanılan aritmetik türüdür. Örneğin 10:00 artı beş saat 03:00 verir. Biçimsel olarak demek istiyoruz ki, Bu denklemin ikinci bölümü 15 modülo 12 denktir 3. şeklinde okunur. Bir ikili operatör olarak da mod ele alınabilir; şöyle ki Daha genel olarak, bir tamsayı a ve pozitif bir tamsayı m için, a mod m benzersiz bir r tamsayısına denktir öyle ki r {0,, m 1} ve herhangi bir k tamsayısı için a = r + km eşitliği sağlanmalıdır. Daha az biçimsel olursak, r değeri a, m e bölündüğünde ortaya çıkan kalandır. Java gibi birçok programlama dillerinde, mod operatörü % sembolü ile temsil edilir.4 4 İlk argüman negatif olduğunda bu doğru matematiksel mod operatörünü uygulamıyor. 43

44 Modüler aritmetik sonsuz bir diziye benzetim yapmak için yararlıdır, çünkü i mod a.length her zaman 0,,a.length 1 aralığında bir değer verir. Modüler aritmetik kullanarak kuyruk elemanlarını aşağıdaki dizi konumlarında saklayabiliriz: Burada a dizisi bir dairesel dizi gibi değerlendirilmektedir. a.length 1 den daha büyük olan dizi endekslerinin dizinin başlangıcına doğru "sarar". Endişelenecek ve dikkat edilmesi gözetilecek tek kalan şey, Dizi Kuyruk elemanlarının sayısı a boyutunu geçmemelidir. Dizi Kuyruk üzerinde ekle (x) ve sil () işlemlerinin örnek bir yürütmesi Şekil 2.2 'de gösterilmiştir. ekle (x) i gerçekleştirmek için öncelikle a nın dolu olup olmadığı kontrol ederiz ve gerekirse, a nın boyutunu artırmak için yeniden_boyutlandır () çağrısı yaparız. Sonra, x değerini a[(j + n) % a.length] içinde saklarız ve n değerini 1 artırırız. sil () işlemini gerçekleştirmek için öncelikle, daha sonra ona geri dönmek üzere a [j] elemanını saklarız. Sonra, n değerini 1 azaltırız ve j = (j + 1) mod a.length ayarlamasıyla j (modülo a.length) değerini 1 artırırız. Son olarak, a [j] konumunda önceden saklamış olduğumuz değeri döndürürüz. Gerekirse, a boyutunu azaltmak için yeniden_boyutlandır () da çağrılabilir. 44

45 45

46 Son olarak, yeniden_boyutlandır () işlemi Dizi Yığıt içinde çalışan yeniden boyutlandırmaya çok benzerdir. Boyutu 2n olan yeni bir b dizisi tahsis eder ve aşağıdaki elemanları şunların üzerine yazar : ve j = 0 olarak ayarlar Özet Aşağıdaki teorem Dizi Kuyruk veri yapısının performansını özetliyor : Teorem 2.2. Bir Dizi Kuyruk, (FIFO) Kuyruk arayüzünü uygular. yeniden_boyutlandır() için yapılan çağrıların maliyeti dikkate alınmayarak, ekle (x) ve sil () işlemleri Dizi Kuyruk tarafından işlem başına O(1) zamanda desteklenir. Ayrıca, boş bir Dizi Kuyruk ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm yeniden_boyutlandır () çağrıları için gerekli toplam çalışma süresi O(m) olur. 46

47 2.4 Dizi İki Başlı Kuyruk: Bir Dizi Kullanan Hızlı İki Başlı Kuyruk İşlemleri Daha önceki bölümlerde elde edilen Dizi Kuyruk dizinin bir ucuna verimli olarak eklenilmesi ve diğer ucundan silinmesini sağlayan bir kuyruğu temsil eden veri yapısıydı. Dizi İki Başlı Kuyruk veri yapısı, her iki uçta da etkili ekleme ve çıkarma yapmaya izin verir. Bu yapı, Dizi Kuyruk u temsil etmek için kullanılan dairesel dizi tekniğinin aynısını kullanarak Liste arayüzünü uygular. Bir Dizi İki Başlı Kuyruk üzerinde çalışan al (i) ve belirle (i, x) işlemlerini gerçekleştirmek kolaydır. Bunlar a[(j + i) mod a.length] konumundaki dizi elemanını getirir veya o değer için atama yapar. 47

48 ekle (i, x) uygulaması biraz daha ilginçtir. Her zamanki gibi, ilk önce a nın dolu olup olmadığını kontrol ediyoruz ve gerekirse, a yı yeniden boyutlandırmak için yeniden_boyutlandır () çağrısı yapmalıyız. i küçük (0 civarında) olduğunda, ya da i büyük (n e yakın) olduğunda, bu işlemin hızlı olmasını istediğimizi unutmayın. Bu nedenle, i < n/2 koşulunu kontrol ederiz. Eğer öyleyse, a[0],,a[i 1] elemanlarını sola doğru 1 konum kaydırırız. Aksi halde (i n/2) iken, a[i],,a[n 1] elemanlarını sağa doğru 1 konum kaydırırız. Dizi İki Başlı Kuyruk üzerinde çalışan ekle(i, x) ve sil (i) işlemlerine bir örnek için Şekil 2.3 e bakınız. 48

49 Bu şekilde kaydırma yaparak, ekle (i,x) işleminin min(i, n i) elemandan fazlasını kaydırmayacağı garanti edilir. Bu nedenle, ekle (i, x) işleminin çalışma süresi (yeniden_boyutlandır () işleminin maliyeti göz ardı edildiğinde) O(1 + min {i, n i}) olur. sil (i) işleminin uygulanması da benzer şekildedir. i < n 2 koşuluna bağlı olarak ya a[0],,a[i 1] elemanlarını sağa doğru 1 konum kaydırılır, ya da a[i + 1],,a[n 1] elemanlarını sola doğru 1 konum kaydırılır. Yine bunun anlamı, sil (i) işleminin elemanları kaydırmak için asla O((1 + min {i, n i}) zamandan daha fazla harcamayacağıdır Özet Aşağıdaki teorem Dizi İki Başlı Kuyruk veri yapısının performansını özetliyor: Teorem 2.3. Bir Dizi İki Başlı Kuyruk, Liste arayüzünü uygular. yeniden_boyutlandır () için yapılan çağrıların maliyeti dikkate alınmayarak, bir Dizi İki Başlı Kuyruk aşağıdaki işlemleri destekler : al (i) ekle (i, x) ve belirle (i, x) işlem başına O(1) zamanda gerçekleşir; ve ve sil (i) işlem başına O((1 + min {i, n i}) zamanda gerçekleşir. 49

50 Ayrıca, boş bir Dizi İki Başlı Kuyruk ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm yeniden_boyutlandır () çağrıları için gerekli toplam çalışma süresi O(m) olur Çifte Dizi İki Başlı Kuyruk : İki Yığıt tan Bir İki Başlı Kuyruk Oluşturulması Şimdi, bir Dizi İki Başlı Kuyruk ile aynı performans sınırını sağlayan, fakat iki adet Dizi Yığıt kullanan ve bu nedenle Çifte Dizi İki Başlı Kuyruk adı verilen bir veri yapısını sunuyoruz. Çifte Dizi İki Başlı Kuyruk un asimptotik performansı Dizi İki Başlı Kuyruk tan daha iyi olmamasına rağmen hala üzerinde düşünmeye ve incelemeye değerdir, çünkü iki basit veri yapısını birleştirerek gelişmiş bir veri yapısının nasıl yapıldığına dair iyi bir örnek sunmaktadır. Çifte Dizi İki Başlı Kuyruk iki adet Dizi Yığıt kullanarak bir listeyi temsil eder. Dizi Yığıt ın listenin uçlarındaki elemanları değiştirdiği zaman hızlı olduğunu hatırlayın. Çifte Dizi İki Başlı Kuyruk front ve back adı verilen karşılıklı birer Dizi Yığıt yerleştirir, böylece işlemler çalıştığında her iki uçta da hızlı olacaktır. Çifte Dizi İki Başlı Kuyruk eleman sayısı olan n i açıkça depolamaz. Buna gerek yoktur çünkü, eleman sayısı, n = front.boyut() + back.boyut() ile bulunur. Yine de, Çifte Dizi İki Başlı Kuyruk u analiz ederken, içerdiği eleman sayısını göstermek için n değişkenini kullanmaya devam edeceğiz. 50

51 front Dizi Yığıt, endeksleri 0,,front.boyut() 1 olan liste elemanlarını saklar ama ters sırada saklar. back Dizi Yığıt, endeksleri front.boyut(),,boyut() 1 olan liste elemanlarını normal sırada saklar. Bu şekilde, al (i) ve belirle (i, x) işlemleri ön ya da arka üzerine yönlendirilerek işlem başına O(1) zamanda çalışacak olan uygun al (i) ve belirle (i, x) çağrılarına çevrilir. Herhangi bir i < front.boyut() koşulunu sağlayan i endeksine ait eleman, front.boyut() i 1 konumundaki front elemanına karşılık gelir, çünkü front elemanlar tersten saklanmaktadır. 51

52 Çifte Dizi İki Başlı Kuyruk a eleman ekleme ve çıkarma Şekil 2.4 'de gösterilmiştir. ekle (i, x) işlemi uygun olması gerekecek şekilde front ya da back yığıtı işler : ekle (i, x) denge () 2 yöntemi denge () yöntemini çağırarak front ve back Dizi Yığıt larını dengeler. uygulanması aşağıda açıklanmıştır, ama şimdilik şunu bilmek yeterlidir: boyut() < olmadığı sürece, dengeleme sonucunda front.boyut() ve back.boyut() değerleri 3 kattan daha fazla farklılaşmazlar. denge () bize bunu garanti eder. Özellikle, 3 front.boyut() back.boyut() ve 3 back.boyut() front.boyut() yazılır. Şimdi, dengele () için yapılan çağrıların maliyetini görmezden gelerek, ekle (i, x) maliyetini analiz edeceğiz. Eğer i<front.boyut() ise, ekle(i, x) yöntemi front.ekle(front.boyut() i 1,x) çağrısı tarafından gerçekleştirilir. front bir Dizi Yığıt olduğu için bunun maliyetini şöyle yazarız : Öte yandan, eğer i front.boyut() ise, ekle(i, x) yöntemi back.ekle(i front.boyut(), x) çağrısı tarafından gerçekleştirilir. Bunun maliyeti, Farkına varmalısınız ki, birinci durum (2.1) i < n/4 koşulunda oluşur. İkinci durum (2.2) i 3n/4 koşulunda oluşur. n/4 i < 3n/4 koşulunda işlemin front ya da back yığıtlarından 52

53 hangisini etkilediğinden emin olamayız, fakat her iki durumda da, i n/4 ve n i > n/4 olduğundan işlem O(n) = O(i) = O(n i) zaman alır. Durumu özetlersek, Bu nedenle, ekle (i, x) çalışma süresi, denge () çağrısının maliyetini görmezden gelirsek, O(1 + min{i, n i }) olur. sil (i) işlemi ve analizi, ekle (x, i) analizi ile benzeşmektedir Dengeleme Son olarak, ekle (i, x) ve sil (x) tarafından gerçekleştirilen dengele () işlemine bakalım. Bu işlem front ve back yığıtlarının ne çok büyük ne de çok küçük olmamasını garanti ediyor. İki elemandan daha az boyutta olmadıkları sürece, front ve back in her birinin en az n/4 eleman içermesini sağlıyor. Bu durum geçerli değilse, o zaman elemanları aralarında yer değiştirerek hareket ettiriyor. Böylece front ve back tam olarak sırasıyla n/2 eleman ve n/2 eleman içeriyor. 53

54 Burada analiz edilmesi gereken çok az şey var. dengele () işlemi dengelemeyi yapıyorsa, o zaman O(n) elemanı bir konumdan başka bir konuma taşımıştır ve bu O(n) zaman alır. Bu kötüdür, çünkü ekle (i, x) ve sil (x) için yapılan her çağrıda dengele () çağrılır. Bununla birlikte, aşağıdaki öneri gösteriyor ki, ortalama olarak, dengele () sadece işlem başına sabit miktarda zaman harcamaktadır. Öneri 2.2. Boş bir Çifte Dizi İki Başlı Kuyruk oluşturulursa ve ekle(i, x) ve sil (i) işlemleri seri olarak m 1 kere çağrılırsa, o zaman dengele () için yapılan tüm çağrılar sırasında harcanan toplam zaman O(m) olur. Kanıt. Eğer dengele () elemanları kaydırmak zorunda kalırsa, son kaydırmadan bu yana çağrılmış bulunan ekle (i, x) ve sil (i) işlemlerinin sayısı en az n/2 1 olur. Öneri 2.1 in kanıtında olduğu gibi, dengele() tarafından harcanan toplam zamanın O(m) olduğunu kanıtlamak için bu yeterlidir. 54

55 Burada potansiyel yöntemi olarak adlandırılan bir teknik kullanarak analizimizi gerçekleştireceğiz. Çifte Dizi İki Başlı Kuyruk un potansiyeli, Ф, front ve back boyutları arasındaki fark olarak tanımlanır. Bu potansiyel hakkında ilginç olan şey şudur ki, dengeleme yapmaya gerek duymayan bir ekle (i, x) ve sil (i) çağrısı potansiyeli en çok 1 artırabilir. Gözlemlemelisiniz ki, elemanları kaydıran bir dengele() çağrısından hemen sonra, potansiyel Ф0, en çok 1 dir, çünkü Elemanları kaydıran bir dengele () çağrısından hemen önceki durumu düşünün ve detayları atlayarak varsayalım ki, 3front.boyut() < back.boyut() olduğu için dengele () elemanları kaydırmaktadır. Bu durumda, farkında olmalısınız ki, Ayrıca, bu andaki potansiyel olur. 55

56 Bu nedenle, dengele () tarafından yapılan son kaydırmadan itibaren ekle (i, x) ve sil (i) işlemlerine yapılan çağrıların sayısı en az Ф1 Ф0 > n/2 1 olur. Bu kanıtlamayı tamamlar Özet Aşağıdaki teorem bir Çifte Dizi İki Başlı Kuyruk un özelliklerini özetlemektedir: Teorem 2.4. Bir Çifte Dizi İki Başlı Kuyruk, Liste arayüzünü uygular. yeniden_boyutlandır() ve dengele() için yapılan çağrıların maliyeti dikkate alınmayarak, bir Çifte Dizi İki Başlı Kuyruk aşağıdaki işlemleri destekler : al (i) ekle (i, x) ve belirle (i, x) işlem başına O(1) zamanda gerçekleşir; ve ve sil (i) işlem başına O((1 + min {i, n i}) zamanda gerçekleşir. Ayrıca, boş bir Çifte Dizi İki Başlı Kuyruk ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm yeniden_boyutlandır () ve dengele () çağrıları için gerekli toplam çalışma süresi O(m) olur. 2.6 Kök Dizi Yığıt: Alan Kriteri Verimli Olan Bir Dizi Yığıt Uygulaması Bu bölümde anlatılan önceki veri yapılarının tümünde ortak sorun, kendi verilerini bir ya da iki dizide depolarken bu dizilerin sık sık boyutlandırılmaması ve çok sık dolu olmamasıdır. Örneğin, Dizi Yığıt üzerinde gerçekleştirilen bir yeniden_boyutlandır () işleminden hemen sonra destek dizisi olan a nın sadece yarısı doludur. Daha da kötüsü, a nın sadece 1/3 oranında veri içerdiği zamanlar vardır. 56

57 Bu bölümde, boşa harcanan alan sorununu ele alan Kök Dizi Yığıt veri yapısını tartışacağız. Kök Dizi Yığıt, n anda en çok elemanı diziyi kullanarak depolar. Bu diziler içinden, herhangi bir dizi konumu kullanılmamıştır. Kalan tüm dizi konumları veri depolamak için kullanılır. Bu nedenle, bu veri yapıları n elemanı saklarken en çok alan kaybetmiştir. Kök Dizi Yığıt, elemanlarını 0, 1,, r 1 olarak numaralandırılan ve blok adı verilen r adet diziden oluşan bir listede depolar. Şekil 2.5 'e bakınız. Blok b, b + 1 elemanı içerir. Bu nedenle, tüm r blokları toplam olarak eleman içerir. Yukarıdaki formül Şekil 2.6 'de gösterildiği gibi elde edilebilir. Tahmin edebileceğimiz gibi, listenin elemanları blok içinde sırayla ortaya konmuştur. Endeksi 0 olan liste elemanı, blok 0 da saklanır, endeksleri 1 ve 2 olan liste elemanları, blok 1 da depolanır, liste endeksleri 3, 4, 5 olan elemanlar blok 2 de depolanır, vb. Üzerinde durmamız gereken temel sorun, endeks i verildiğinde hangi bloğun i içerdiğini ve hem de bu blok içinde i ye karşılık gelen endeksi belirlemektir. Kendi bloğu içinde i endeksini belirlemek kolaydır. i endeksi b bloğunun içinde ise o zaman blok 0, 1,, b 1 içinde bulunan elemanların sayısı b(b+1)/2 olur. Bu nedenle, i, b bloğu içinde konumunda saklanmıştır. Biraz daha zor olanı b değerini belirleme sorunudur. Endeksi i den daha az ya da eşit olan elemanların sayısı i + 1 e eşittir. Diğer taraftan, 0,, b bloklarındaki 57

58 elemanların sayısı (b+1)(b+2)/2 dir. Bu nedenle, b, koşulunu sağlayan en küçük tamsayıdır. Bu denklemi 58

59 olarak tekrar yazabiliriz. Buna karşılık gelen b2 + 3b 2i = 0 ikinci dereceden denkleminin iki çözümü vardır : ve İkinci çözüm bizim uygulamamız için hiç mantıklı gelmiyor, çünkü her zaman negatif bir değer verir. Bu nedenle, çözümünü elde ederiz. Genel olarak, bu çözüm bir tam sayı değildir, ama eşitsizliğimize geri gidersek, biz koşulunu sağlayan en küçük tamsayı olan b yi istiyoruz. Basitçe bu, olur. Bu şekilde al (i) ve belirle (i, x) yöntemlerini yapmak karmaşık değildir, anlaması kolaydır. İlk olarak, uygun b bloğunu ve blok içindeki uygun j endeksini hesaplarız ve daha sonra uygun işlemi gerçekleştiririz : 59

60 Blok listesini temsil etmek için bu bölümdeki veri yapılarından herhangi birini kullanmışsak, o zaman al (i) ve belirle (i, x) işlemlerinin her ikisi de sabit sürede çalışacaktır. ekle (i, x) yöntemi, artık, tanıdık gelecektir. Öncelikle blok sayısının r(r+1) / 2 = n eşitliğini sağlayıp sağlamadığını kontrol ettikten sonra, veri yapısının tam dolu olup olmadığını belirleriz. Burada r blok sayısıdır. Eğer eşitlik sağlanmışsa, başka bir blok eklemek için büyült () çağrısı yaparız. Bu işlem ile endeksi i olan yeni elemana yer açmak için i,,n 1 endeksli elemanları 1 konum sağa kaydırırız. büyült () yöntemi beklendiği gibi, yeni bir blok ekler : Büyültme işleminin maliyetini görmezden gelerek, bir ekle (i, x) işleminin maliyetinin en önemli parçası kaydırmanın maliyetidir ve bu yüzden bir Dizi Yığıt daki gibi sadece O(1+n i) zaman alır. sil (i) işlemi ekle (i, x) işlemine benzerdir. i+1,,n endeksli elemanları 1 konum sola kaydırır, ve daha sonra, kullanılmayan blokların birini kaldırmak için küçült () yöntemini çağırır. 60

61 Bir kez daha, küçült () işleminin maliyeti görmezden gelinerek, sil (i) işlemine ait maliyetin en önemli parçası kaydırmanın maliyetidir ve bu nedenle O(n - i) çalışma süresi vardır Büyültme ve Küçültmenin Analizi ekle (i, x) ve sil (i) ile ilgili yaptığımız yukarıdaki analizde büyült () ve küçült () maliyetini hesaba katmamıştık. Unutmayın ki, Dizi Yığıt.yeniden_boyutlandır () yönteminin aksine, büyült () ve küçült () herhangi bir veri kopyalamaz. Sadece r boyutlu bir diziyi tahsis eder veya boşaltır, temizler. Bazı ortamlarda, bu sadece sabit zaman alırken, diğerlerinde ise, r orantılı zaman gerektirebilir. büyült () veya küçült () çağrısından hemen sonra durum açıktır. Son blok tamamen boştur ve diğer tüm bloklar tamamen doludur. En az r 1 elemanlar eklenene veya çıkarılana kadar büyült () veya küçült () için başka bir çağrı yapılmayacaktır. Bu nedenle büyült() ve küçült() işlemleri O(r) zaman alsa bile bu maliyet en az r 1 adet ekle (i, x) veya sil (i) işlemi üzerinden amortize edilebilir, böylece büyült () ve küçült () ün işlem başına amortize maliyeti O(1) olur. 61

62 2.6.2 Alan Kullanımı Şimdi, bir Kök Dizi Yığıt tarafından kullanılan ekstra alan miktarını analiz ediyoruz. Özellikle, bir Kök Dizi Yığıt tarafından kullanılan ve şu anda bir liste elemanını tutmak için kullanılmayan dizi elemanlarının kapladığı alanı saymak istiyoruz. Bu tür alana israf alanı diyoruz. sil (i) işlemi, bir Kök Dizi Yığıt ın asla tamamen dolu olmayan iki bloktan daha fazlasına sahip olmayacağını garanti eder. Bu nedenle n elemanı saklayan bir Kök Dizi Yığıt tarafından kullanılan blok sayısı, r, koşulunu sağlar. Bunu ikinci dereceden denklem olarak çözersek, elde edilir. Son iki bloğun boyutları r ve r 1 dir. Bu yüzden bu iki blok tarafından israf edilen alan en fazla olur. Biz, (örneğin) bir Dizi Liste de blokları depoladığımız takdirde, o zaman r bloğu depolayan Liste tarafından israf edilen alan miktarı olur. n ve diğer sistematik kayıtları depolamak için gerekli alanlar O(1) dir. Bu nedenle, bir Kök Dizi Yığıt da israf edilen toplam alan miktarı olur. Sonra, bu alan kullanımının boş başlayan herhangi bir veri yapısı için uygun olduğunu ve her seferinde bir eleman eklenmesini destekleyebildiğini iddia ediyoruz. Daha kesin bir ifadeyle, n elemanın eklenmesi sırasında bir noktada, veri yapısının, en az miktarında bir boşluğu israf ettiğini göstereceğiz (gerçi sadece bir an için israf edilebilse de). Boş bir veri yapısı ile başladığımızı varsayalım ve her seferinde bir tane olmak üzere toplam n elemanı ekliyoruz. Bu işlemin sonunda, n elemanın tamamı veri yapısında depolanmış ve r bellek bloklarının arasına dağıtılmış olacaktır. Eğer koşulu doğru ise, o zaman veri yapısının bu r bloğu izlemek için r gösterge (veya referans) kullanıyor olması gerekir, ve bu göstergeler alanı israf edilmektedir. Öte yandan, 62 koşulu doğruysa, güvercin deliği

63 ilkesi ile, bir blok en azından boyuta sahip olmalıdır. Bu bloğun ilk tahsis edildiği anı düşünün. Bu tahsisten hemen sonra, bu blok boştu, ve bu nedenle alanı israf ediyordu. Bu nedenle, n elemanların yerleştirilmesi sırasında zaman içinde bir noktada veri yapısı alanı israf ediyordu Özet Aşağıdaki teorem Kök Dizi Yığıt veri yapısı ile ilgili tartışmamızı özetliyor : Teorem 2.5. Bir Kök Dizi Yığıt, Liste arayüzünü uygular. büyült () ve küçült () çağrılarının maliyetini dikkate almayarak, Kök Dizi Yığıt işlem başına O(1) zamanda çalışan al (i) ve belirle (i, x); ve işlem başına O(1 + n i) zamanda çalışan ekle (i, x) ve sil (i) işlemlerini destekler. Bundan başka, boş bir Kök Dizi Yığıt ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm büyült () ve küçült () çağrıları için gerekli toplam çalışma süresi O(m) olur. n elemanı depolayan bir Kök Dizi Yığıt tarafından kullanılan alan5 (sözcük cinsinden ölçüldüğünde) dir Karekökleri Hesaplamak Hesaplama modellerini biraz bilen bir okuyucu, fark etmiştir ki, yukarıda anlatıldığı gibi bir Kök Dizi Yığıt her zamanki sözcük-ram hesaplama modeline uymuyor (Bölüm 1.4) çünkü bu karekök almayı gerektirir. Karekök işlemi genellikle bir temel işlem olarak kabul edilmez ve bu nedenle çoğu zaman sözcük-ram modelinin bir parçası değildir. 5 Belleğin nasıl ölçüldüğünü Bölüm 1.4 teki tartışmadan hatırlayın. 63

64 Bu bölümde, karekök işleminin etkin bir şekilde uygulanabilir olduğunu göstereceğiz. Özellikle herhangi bir tamsayı x {0,, n} için, önişlemesinden sonra uzunluğunda iki dizi yaratan in sabit bir sürede hesaplanabileceğini göstereceğiz. Aşağıdaki önerme göstermektedir ki x'in karekökünü hesaplama sorunu ilgili bir x değerinin kare köküne indirilebilir. Öneri 2.3. iken x 1 ve x = x a olsun. O zaman olur. Kanıt. Şunun doğru olduğunu göstermek yeterlidir : Bu eşitsizlikte her iki tarafın karesi alındığında, elde ederiz. Terimleri bir araya getirdiğimizde, herhangi bir x 1 için açıkça doğru olan elde edilir. Problemi biraz daraltarak başlayın, ve varsayın ki 2r x 2 r+1 için log x = r, yani, x ikili gösterimi r + 1 bit olan bir tam sayıdır. Kabul edebiliriz ki, x = x ( x mod 2 r / 2 ). Şimdi, x Öneri 2.3 ün koşullarını yerine getirmektedir, dolayısıyla. Ayrıca, x değerini oluşturan r/2 alt sıralı bitin hepsi 0 a eşittir, yani mümkün olabilen her x değeri için söylenebilir. Bu olası her x değeri için nun değerini depolayan sqrttab adında bir dizi kullanabileceğimiz anlamına gelir. Biraz daha doğrusunu söylemek gerekirse, 64

65 değerlerine sahibiz. Bu şekilde, sqrttab[i] her x { i2 r/2,,(i+1)2 r/2 1 } için in 2 değeri ile sınırlanmıştır. Diğer bir deyişle, s = sqrttab[x>> r/2 ] girişindeki dizi elemanının değeri ya ya da olur. s yardımıyla değerini de belirleyebiliriz. Bunun için s değeri (s+1)2 > x olana kadar artırılır. Şimdi, bu sadece x { 2r,, 2r+1 1 } için çalışır ve sqrttab sadece belirli bir r = log x değeri için çalışan özel bir tablo olmuştur. Bunun üstesinden gelmek için, olası her log x değeri için birer tane olacak şekilde log n adet farklı sqrttab dizisi hesaplayabiliriz. Bu tabloların boyutları incelendiğinde, en büyük değeri yani tüm tabloların toplam boyutu olan bir üstel dizi ile karşılaşılır, olur. Ancak, birden fazla sqrttab dizisinin gereksiz olduğu ortaya çıkar; sadece r = log n değeri için bir sqrttab dizisine gerek duyarız. log x = r < r denklemini sağlayan herhangi bir x değeri 2r-r ile çarpıldığında ve denklemi kullanılarak yükseltilebilir. 2 r-r x miktarı { 2r,, 2r+1 1 } aralığındadır, bu yüzden onun karekökünü sqrttab içinde arayabiliriz. Aşağıdaki kod bu fikri, { 0,, } aralığındaki negatif olmayan tüm x tamsayıları için ve 216 büyüklüğünde bir sqrttab dizisi kullanarak, için gerçekleştirmiştir. 65 değerini hesaplamak

66 Şimdiye kadar sorgusuz sualsiz doğru olduğunu varsaydığımız şey, r = log x in nasıl hesaplanacağı sorusudur. Bu yine, 2r/2 boyutunda bir dizi, logtab, ile çözülebilecek bir sorundur. Bu durumda, kod, özellikle basittir, çünkü log x x in ikili gösteriminde en önemli 1 bit inin sadece endeksidir. Bu demektir ki, logtab dizininde bir endeks olarak kullanılmadan önce, x > 2r/2 için x bitlerini r/2 pozisyonu kadar sağa kaydırabiliriz. Aşağıdaki kod 216 büyüklüğünde bir logtab dizisini kullanarak { 0,, } aralığındaki tüm x için log x değerini hesaplamaktadır. Son olarak, eksiksiz olmak için, logtab ve sqrttab dizilerini ilk kullanıma hazırlayan aşağıdaki kodu ekliyoruz : 66

67 Özetlemek gerekirse, i2b (i) yöntemi ile yapılan hesaplamalar sözcük-ram üzerinde sqrttab ve logtab dizilerini depolamak için gerekli olan ekstra bellek kullanarak sabit zamanda gerçekleştirilebilir. n iki kat arttığı veya azaldığı zaman bu diziler yeniden inşa edilebilir ve bu yeniden inşa maliyeti Dizi Yığıt uygulamasında analiz edilen yeniden_boyutlandır () maliyetiyle aynı şekilde n de değişikliğe sebep olan ekle (i, x) ve sil (i) işlemlerinin sayısı üzerinden amortize edilebilir. 2.7 Tartışma ve Alıştırmalar Bu bölümde açıklanan veri yapılarının çoğunda 30 yıl geriye uzanan uygulamalarda rastladığımız benzerlik ve çeşitlilik bulunmaktadır. Örneğin, Yığıt, Kuyruk ve Çift Başlı Kuyruk bu bölümde açıkladığımız Dizi Yığıt, Dizi Kuyruk ve Çifte Dizi İki Başlı Kuyruk yapılarına kolayca genellenebilir. Knuth bu yapıların gerçekleştirimlerini [46, Bölüm 2.2.2] de tartışmıştır. Kök Dizi Yığıt ı deki gibi ilk olarak Brodnik ve arkadaşlarının [13] tanımlamış oldukları ve Bölüm bir alt-sınırı ispatladıkları görülmektedir. Onlar aynı zamanda i2b (i) yöntemindeki karekök işlemini önlemek amacıyla blok boyutlarının daha karmaşık seçildiği farklı bir yapı ortaya koymuşlardır. Onların tasarımında, i nin dahil olduğu blok ile endekslenen bloktur. Endeksi ise i+1 in ikili tabanda ifadesinin en başında yer alan 1 bitinin lokasyonudur. Bazı bilgisayar mimarileri bir tamsayının başında gelen 1-bitinin lokasyonunu hesaplayan komutu otomatik olarak sağlar. Kök Dizi Yığıt ile ilgili bir yapı da Goodrich and Kloss un iki seviyeli katmanlı vektörüdür [35]. Bu yapı al (i, x) ve belirle(i, x) işlemlerini sabit sürede ve ekle (i, x) ve sil (i) işlemlerini zamanda destekler. Alıştırma 2.11 de tartışılan Kök Dizi Yığıt ın daha dikkatli bir gerçekleştiriminden elde edilen çalışma zamanlarının benzeridir. Alıştırma 2.1. Dizi Yığıt uygulamasında sil (i) metoduna yapılan ilk çağrı sonrasında a arkalık dizisi Dizi Yığıt sadece n eleman saklamasına rağmen n + 1 boş olmayan değeri içerir. Ekstra 67

68 boş olmayan değer nerededir? Bu boş olmayan değerin, Java Çalıştırma Ortamı bellek yöneticisinde olması hangi sonuçları getirir? Tartışın. Alıştırma 2.2. Liste veri yapısının yöntemlerinden hepsiniekle (i, c) her bir toplanmış veri c elemanını listenin i pozisyonuna ekler. (ekle (i, x) yöntemi c = {x} olan bir özel durumdur.) Bu bölümdeki veri yapıları için hepsiniekle (i, c) yöntemini yinelenen ekle (i, x) çağrıları ile gerçekleştirmenin niçin verimli olmadığını açıklayın. Daha verimli bir uygulamayı tasarlayın ve uygulayın. Alıştırma 2.3. Bir Rasgele Kuyruk tasarlayın ve uygulayın. Bu, sil () işleminin şu anda kuyrukta yeralan tüm elemanlar arasında rasgele eşitlikte seçilmiş bir öğeyi kaldırdığı Kuyruk arayüzünün bir uygulamasıdır. (Rasgele Kuyruk u öğeleri eklemek veya ulaşmak ve körü körüne bazı rasgele elemanları çıkarmak için herhangi bir torba (bag) gibi bir düşünün.) Bir Rasgele Kuyruk un ekle (x) ve sil () işlemleri işlem başına sabit zaman çalışmalıdır. Alıştırma 2.4. Bir Üç Uçlu Kuyruk u tasarlayın ve uygulayın. Bu al(i) ve belirle(i, x) işlemlerinin sabit zamanda çalıştığı ve ekle (i, x) ve sil (i) işlemlerinin zamanda çalıştığı bir Liste uygulamasıdır. Diğer bir deyişle, her iki uca yakınsa veya liste ortasına yakın ise değişiklikler hızlı olur. Alıştırma 2.5. a dizisinin elemanlarını dönüştürerek yer değiştirmesini sağlayan elemanyerdönüştür (a, r) yöntemini her i {0,, a.length} için a [i] pozisyonundaki elemanın gideceği yer a [(i + r) mod a.length] olacak şekilde uygulayın. Alıştırma 2.6. Liste elemanlarının yerlerini dönüştürerek değiştirecek bir elemanyerdönüştür (r) yöntemini i pozisyonundaki bir liste elemanının yeri (i + r) mod n pozisyonunda olacak şekilde gerçekleştirin. Dizi İki Başlı Kuyruk veya Çifte Dizi İki Başlı Kuyruk üzerinde çalıştırdığınızda elemanyerdönüştür (r) yönteminin çalışma zamanı O(1 + min {r, n r}) olmalıdır. 68

69 Alıştırma 2.7. Dizi İki Başlı Kuyruk gerçekleştirimini ekle (i, x), sil (i), ve yeniden_boyutlandır () tarafından Sistem.arraycopy(s, i, d, j, n) yapılan kaydırmayı daha hızlı yapmak için yöntemini kullanarak değiştiriniz. Alıştırma 2.8. Dizi İki Başlı Kuyruk gerçekleştirimini % operatörünü kullanmayacak şekilde uygulayın (nedeni bu bazı sistemlerde pahalıdır). Bunun yerine, a.length 2 üssü bir sayıysa eşitliğinden yararlanmak gerekir. (Burada, & bit-bit-ve operatörüdür.) Alıştırma 2.9. Hiç bir modüler aritmetik yapmayan Dizi İki Başlı Kuyruk gerçekleştirimini tasarlayın ve uygulayın. Bunun yerine, tüm veriler, bir dizi içinde, sırayla, ardışık blok içinde oturur. Veri bu dizinin başlangıcına ya da sonuna taştığı zaman, yeniden_inşa() işlemi gerçekleştirilir. Tüm işlemlerin amortize edilmiş maliyeti Dizi İki Başlı Kuyruk ile aynı olmalıdır. Alıştırma İsraf alanı sadece olan, ancak ekle (i, x) ve sil (i, x) işlemlerini O(1 + min {i, n - i} ) zamanda gerçekleştirebilen bir Kök Dizi Yığıt versiyonunu tasarlayın ve uygulayın. Alıştırma İsraf alanı sadece olan, ancak ekle (i, x) ve sil (i, x) işlemlerini zamanda gerçekleştirebilen bir Kök Dizi Yığıt versiyonunu tasarlayın ve uygulayın (Fikir edinmek için, bakınız Bölüm 3.3.) Alıştırma İsraf alanı sadece olan, ancak ekle (i, x) ve sil (i, x) işlemlerini zamanda gerçekleştirebilen bir Kök Dizi Yığıt versiyonunu tasarlayın ve uygulayın (Fikir edinmek için, bakınız Bölüm 3.3.) Alıştırma Bir Kübik Dizi Yığıt tasarlayın ve uygulayın. Bu üç seviyeli yapıda Liste arayüzünün kullandığı israf alanı O(n2/3) iken ekle (i, x) ve sil (i) işlemlerinin amortize çalışma zamanı O(n1/3) olur. al (i) ve belirle (i, x) işlemleri sabit zamanda çalışır. 69

70 Bölüm 3 Bağlantılı Listeler Bu bölümde, Liste arayüzünün uygulamalarını çalışmaya devam edeceğiz, bu kez dizi tabanlı veri yapılar yerine işaretçi-tabanlı veri yapılarını kullanacağız. Bu bölümde inceleyeceğimiz yapılar liste elemanlarını içeren düğümlerden oluşmaktadır. Düğümler referanslar (işaretçiler) yoluyla bir dizi halinde bir araya bağlanır. Biz ilk olarak tek başına-bağlı listeleri çalışacağız. Bu yapı Yığıt ve (FIFO) Kuyruk işlemlerini işlem başına sabit zamanda çalıştırır. Daha sonra çifte-bağlantılı listelere geçeceğiz. Bu yapı İki Başlı Kuyruk işlemlerini sabit zamanda çalıştırır. Liste arayüzünün dizi tabanlı uygulamalarını bağlantılı listeler ile kıyasladığımızda bazı avantaj ve dezavantajlar ile karşılaşırız. Birinci dezavantajı herhangi bir elemana erişmek için sabit zamanlı al (i) ve belirle (i, x) işlemlerini kullanma yeteneğimiz kaybedilebilir. Bunun yerine, i'nci elemana ulaşana kadar liste üzerindeki her bir eleman üzerinden yürümek zorunda kalırız. En önemli avantajı ise, daha dinamik olmasıdır: u herhangi bir liste düğümü olduğu takdirde u listenin hangi pozisyonunda olursa olsun, u için bir referans verilirse, u silinebilir veya u ya bitişik bir düğüm sabit zaman içinde eklenebilir. 3.1 TBListe: Tekli-Bağlantılı Liste Bir TBListe (tekli-bağlantılı liste) bir dizi Düğüm den oluşur. Her u düğümü bir u.x verisi ve dizideki bir sonraki düğüme u.next işaretçisi saklar. Dizinin son düğümü w için, w.next = null olur. 70

71 Verimliliği artırmaya yarayan head ve tail değişkenleri birinci ve son düğümü izlemek için kullanılır. Bunun yanı sıra dizinin uzunluğunu takip etmek için bir n tamsayısı kullanılır: TBListe üzerinde gerçekleştirilebilen Yığıt ve Kuyruk işlemlerinden bazıları Şekil 3.1 'de gösterilmiştir. Dizinin başındaki elemanları ekleyerek ve çıkararak yığ () ve yığıttan kaldır () Yığıt işlemleri TBListe tarafından verimli şekilde gerçekleştirilir. yığ () işlemi basitçe veri değeri x olan yeni bir düğüm u oluşturur, bunu u.next değişkenini kullanarak eski listeye ekler ve u listenin yeni başı olur. En sonunda n bir artırılır çünkü TBListe in boyutu bir artmıştır: 71

72 yığıttan kaldır () işlemi, TBListe düğümlerinin boş olmadığı kontrol edildikten sonra listenin başını head=head.next olarak belirler ve n bir azaltılır. Son eleman kaldırılırken özel bir durum oluşur ki burada, listenin sonu tail=null olarak belirlenmiştir. Açıktır ki, yığ (x) ve yığıttan kaldır () işlemlerinin her ikisi de O (1) zamanda çalışıyor Kuyruk İşlemleri Bir TBListe ekle (x) ve sil () FIFO Kuyruk işlemlerini sabit zamanda gerçekleştirir. Çıkarma listenin başından yapılır, ve yığıttan kaldır () işlemi ile eşdeğerdir: 72

73 Diğer yandan, eklemeler listenin sonundan yapılır. Çoğu durumda, bu tail.next = u belirlenmesi ile gerçekleştirilir, burada u, x verisini içeren yeni oluşturulan düğümdür. Ancak n=0 olduğunda, özel bir durum ortaya çıkar. Bu özel durumda tail = head = null olarak belirlenmiştir. Ekleme sonucunda, hem tail ve hem de head, u olarak ayarlanır. Açıktır ki, ekle (x) ve sil () işlemlerinin her ikisi de O (1) zamanda çalışıyor Özet Aşağıdaki teorem TBListe performansını özetler: Teorem 3.1. Bir TBListe, Yığıt ve (FIFO) Kuyruk arayüzlerini uygular. yığ(x), yığıttan kaldır(), ekle(x) ve sil() işlemleri işlem başına O(1) zamanda çalışır. Bir TBListe neredeyse İki Başlı Kuyruk işlemlerinin tam setini uygular. Tek eksik işlem TBListe düğümlerinin sonuncusunu ortadan kaldırmaktır. Son TBListe düğümünün silinmesi zordur, çünkü öyle bir şekilde güncellenmesi gerekir ki bu, TBListe içindeki sondan bir önceki w düğümüne işaret etsin, bu w.next = tail olan w düğümüdür. Ne yazık ki, w ya ulaşmak için tek yol TBListe in en başındaki düğümden başlayarak adım adım takip edilmesi ve en sonunda n-2 adım geriye gitmektir. 73

74 3.2 ÇBListe: Çifte-Bağlantılı Liste Bir ÇBListe (çifte-bağlantılı liste) TBListe ye çok benzer, ancak ÇBListe deki her u düğümünün onun ardından gelen u.next ve öncesinden gelen u.prev bağlantıları mevcuttur. Bir TBListe uygulamasında, endişelenecek sadece birkaç özel durum olduğunu gördük. Örneğin, son elemanı silmek, ya da boş bir TBListe ye eleman eklenmesi listenin baş ve son elemanlarının doğru olarak güncellenmesini gerektirir. ÇBListe ye baktığımızda özel durumların sayısı önemli ölçüde artmıştır. Belki de bir ÇBListe için tüm bu özel durumların üstesinden gelmenin en temiz yolu bir dummy düğüm tanıtmaktır. Bu herhangi bir veri içermeyen bir düğüm olarak tanımlanır, sadece bir yer tutucu görevi görür. Bu sayede özel düğüm kavramı ortadan kalkmış olur; her düğümün bir sonraki ve bir önceki bağlantısı mevcut olur. Listedeki son düğümü izleyen düğüm dummy düğüm olarak adlandırdığımız düğümdür. Listedeki ilk düğümden önce gelen düğüm yine dummy düğüm olarak adlandırdığımız düğümdür. Böylece, Şekil 3.2 de gösterildiği gibi listenin düğümleri, bir döngü içine iki kat olmak üzere çifte bağlanmıştır. Belirli bir endeks pozisyonundaki ÇBListe elemanını bulmak zor değildir, biz ya listenin başından başlayabiliriz (dummy.next) ve ileri yönde çalışırız, ya da listenin sonundan başlar (dummy.prev) ve geri yönde çalışırız. Bu bize i'nci düğüme erişmek için O(1+min {i, n i}) zaman gerektirir: 74

75 al (i) ve belirle (i, x) işlemleri de artık kolaydır. Gerçekleştirmek için ilk olarak i'nci düğümü buluruz ve daha sonra x değerini alır ya da belirleriz. Bu işlemlerin çalışma zamanı i nci düğümü bulmak için gerekli zaman ile sınırlıdır, ve bu nedenle O(1+min {i, n i}) olur Ekleme ve Çıkarma Bir ÇBListe de yer alan w düğümüne başvuru yapıldıysa, ve w düğümünden önce bir u düğümü eklemek istiyorsak, o zaman basitçe u.next=w ve u.prev = w.prev olarak belirlendikten sonra gerekli u.prev.next ve u.next.prev ayarlamaları yapılmalıdır (bkz. Şekil 3.3). Dummy düğüm sayesinde, w.prev ve w.next in mevcut olmaması durumları ihtimal dahilinde değildir. 75

76 ekle (i, x) liste işlemini gerçekleştirmek şimdi çok basittir. ÇBListe de yer alan i nci düğümü buluruz. x verisini taşıyan yeni bir u düğümünü hemen öncesinden ekleriz. ekle(i, x) işleminin sabit olmayan tek çalışma süresi bileşeni bu i'nci düğümü bulmak için gereken zamandır ( aldüğüm (i) kullanarak). Bu nedenle, ekle (i, x) O(1+min {i, n i}) zamanda çalışır. ÇBListe den bir w düğümünü silmek kolaydır. Sadece w.prev ve w.next işaretçilerini ayarlamamız gereklidir; öyle ki listenin geri kalanı w düğümünü atlasın. Yine, dummy düğümün kullanımıyla herhangi bir özel durumu dikkate alma ihtiyacı ortadan kalkar: Şimdi sil (i) işlemi çok kolaydır. i endeksli düğümü bulup listeden çıkarırız: 76

77 Yine, bu işlemin sadece en pahalı bileşeni aldüğüm (i) kullanarak i nci düğümü bulmaktır. Bu nedenle, sil (i) O(1+min {i, n i}) zamanda çalışır Özet Aşağıdaki teorem ÇBListe performansını özetler: Teorem 3.2. Bir ÇBListe, Liste arayüzünü uygular. Bu gerçekleştirimde al(i), belirle(i, x), ekle(i, x) ve sil(i) işlemleri işlem başına O(1+min {i, n i}) zamanda çalışır. Değinilmesi gereken bir konu da, aldüğüm (i) işlem maliyeti görmezden gelinirse, o zaman tüm ÇBListe işlemleri sabit zaman alır. Bu durumda, bir ÇBListe üzerindeki işlemlerin tek pahalı bileşeni ilgili düğümü bulmaktır. İlgili düğüme eriştikten sonra, düğüm ekleme, silme, ya da o düğüme ait veri erişimi sadece sabit zaman alır. Bu Bölüm 2 deki dizi tabanlı Liste uygulamalarının zıttıdır. Bu gerçekleştirimlerde, ilgili dizi elemanı sabit bir süre içinde bulunabilmektedir. Bununla birlikte, ekleme veya silme dizide elemanların yerlerinin değişmesini gerektirdiği için genel olarak, sabit olmayan bir zaman almaktadır. Bağlantılı liste yapıları liste düğümlerine referansların dış yollarla elde edilebildiği uygulamalar için çok uygundur. Bunun bir örneği, Java Koleksiyonlar Çerçevesi nde bulunan LinkedHashSet veri yapısıdır. Bu yapıda bir dizi eleman çifte bağlı listede saklanır ve çifte- bağlantılı liste düğümleri (Bölüm 5 te tartışılan) karma bir tabloda saklanır. Bir LinkedHashSet elemanını silmek istediğinizde, karma tablo sabit zamanda ilgili liste düğümünü bulmak için kullanılır ve daha sonra listedeki düğüm sabit bir süre içinde silinir. 77

78 3.3 AVListe: Alan-Verimli Liste Bağlantılı listelerinin sorunlardan biri (listenin derinlerinde olan elemanlara erişmek için gereken zaman yanında) kullanım alanı ile ilgilidir. Bir AVListe nin her düğümü kendisinden sonraki ve önceki düğümlere ait iki ek başvuru gerektirir. Bir düğümün iki bilgi alanı listenin bakımı için ve sadece bir alan veri depolamak için ayrılmıştır! Bir AVListe (alan-verimli liste), basit bir fikir kullanarak harcanan bu alanı azaltır: Liste elemanlarını bir ÇBListe de saklamak yerine, çeşitli elemanları içeren (dizi) blokta saklarız. Daha doğrusu, bir AVListe bir blok boyutu b tarafından parametrelendirilmiştir. Bir AVListe de yer alan her tek düğüm b + 1 elemana kadar tutabilecek alana sahip bir blok saklar. Daha sonra açık hale gelecek nedenlerden dolayı, eğer her blokta İki Başlı Kuyruk işlemlerini yapabilirsek yararlı olacaktır. Bunun için seçtiğimiz veri yapısı Bölüm 2.4 'de anlatılan Dizi İki Başlı Kuyruk Kuyruk küçük yapısından türetilmiş olan Sınırlı İki Başlı Kuyruk tur. Sınırlı İki Başlı bir şekilde Dizi İki Başlı Kuyruk tan farklıdır: Yeni bir Sınırlı İki Başlı Kuyruk oluşturulduğunda, destek dizi olan a dizisinin büyüklüğü b + 1 ile sabitlenmiştir, boyutu hiçbir zaman artmaz ya da azalmaz. Bir Sınırlı İki Başlı Kuyruk un önemli bir özelliği elemanları başa veya sona sabit zamanda eklemeye veya silmeye olanak tanımasıdır. Elemanların bir bloktan bir başka bloğa kaydırılması esnasında bu özellikten yararlanacağız. Bunun anlamı, bir AVListe çifte-bağlantılı liste bloklarından oluşmaktadır: 78

79 3.3.1 Alan Gereksinimleri Bir bloğun eleman sayısına bir AVListe çok sıkı kısıtlamalar getirmektedir: Bir blok son blok olmadığı sürece, o blok en az b 1 ve en çok b + 1 eleman içerir. Bunun anlamı bir AVListe n eleman içeriyorsa, o zaman blok sayısı en fazla olur. Her blok için Sınırlı İki Başlı Kuyruk b + 1 uzunluğunda bir dizi içerir, ancak, sonuncu blok dışındaki her blok için, en fazla sabit miktarda bir alan bu dizide israf edilmektedir. Bir blok tarafından kullanılan bellek de sabittir. Bunun anlamı, bir AVListe de israf edilen alan sadece O(b + n/b) dir. Sabit bir faktörü içinde bir b değeri seçerek biz AVListe nin alan- gereksinimini Bölüm 'de verilen alt sınırına yaklaştırabiliriz. Elemanların Bulunması Biz AVListe ile yüzleştiğimizde ilk motivasyonumuz, belirli bir i endeksine ait liste elemanını bulmaktır. Bir elemanın listedeki yerini oluşturan iki bölüm şunlardır: 1. i endeksli elemanı içeren bloğu içeren u düğümü; ve 2. kendi bloğu içinde elemanın j endeksi. 79

80 Belirli bir öğeyi içeren bir bloğu bulmak için, ÇBListe de olduğu gibi aynı şekilde devam etmeliyiz. Ya listenin başından başlayıp ileri yönde hareket edeceğiz, veya listenin arkasından başlayıp istenen düğüme ulaşana kadar geriye doğru hareket edeceğiz. Bir düğümden ötekine geçerken bütün bloğu bir seferde atlarız. Unutmayın ki, en fazla bir blok dışında, her blok en az b - 1 eleman içerir, bu nedenle aramamız sırasında atılan her adım bizi aradığımız elemana b - 1 eleman kadar yaklaştırır. İleriye doğru arama yapıyorsanız, O(1 + i / b) adım sonrasında istediğimiz düğüme ulaşılması anlamına gelir. Geriye doğru arama yapıyorsanız, O(1 + (n i) / b) adım sonrasında istediğimiz düğüme ulaşılması anlamına gelir. Algoritma, i değerine bağlı olarak 80

81 bu iki miktarın daha küçüğünü alır, böylece i endeksli elemanı bulmak için gereken zaman O(1 + min { i, n i } / b ) olur. i endeksli elemanı nasıl bulacağımızı biliyorsak, al (i) ve belirle (i, x) işlemleri doğru blokta belirli bir endeksi almayı veya belirlemeyi gerektirir: Bu işlemlerin çalışma zamanları, elemanı bulmak için gereken zaman ile kısıtlanmıştır, bu nedenle O(1 + min { i, n i } / b ) zamanda çalışır Elemanların Eklenmesi Bir AVListe ye eleman eklenmesi biraz daha karmaşıktır. Genel durumu dikkate almadan önce, daha kolay olan x elemanının listenin sonuna eklendiği ekle (x) işlemini gözden geçirelim. Son blok doluysa, (veya hiç bir blok henüz mevcut değilse) o zaman önce yeni bir blok tahsis ederiz, ve blok listesine ekleriz. Şimdi son bloğun var olduğundan ve onun boş olmadığından emin halde x elemanını bu bloğa ekleriz. 81

82 ekle (i, x) kullanarak listenin içinde bir yere eleman eklediğimizde işler biraz daha karışık hale gelir. i'nci liste elemanını içeren u düğümünün bloğuna erişmek için ilk olarak i bulunur. u bloğunun içine x elemanını eklemek sorununu çözmek için u bloğunun zaten b + 1 eleman içerdiği dolu durumu için hazırlıklı olmak zorundayız. Bunun anlamı x için o blokta yer olmadığıdır. u0, u1, u2,... düğümlerinin işaretçilerini u, u.next, u.next.next olarak belirleyelim. u0, u1, u2, düğümlerinin x elemanını eklemek için bir alan sağlamasını araştırırken üç durum oluşabilir (bkz. Şekil 3.4): 1. Dolu olmayan bir ur düğümünü hızlıca ( r + 1 b adımda) buluruz. ur düğümüne ait bloktan diğerine r eleman yer değiştirir, böylece x elemanını eklemek için ur düğümünde serbest alan oluşmuş oluyor. 2. Hızlıca ( r + 1 b adımda) bulduğumuz blok listelerinin sonuna geliriz. Bloğun sonuna yeni bir boş blok ekleriz ve birinci halde olduğu gibi devam ederiz. 3. Dolu olmayan bir ur düğümünü bulamıyoruz. Bu durumda, u0,, ub-1 b adet bir dizi bloğudur. Bu blokların her biri b + 1 eleman içerir. En son bloğun ardına yeni bir blok ub bloğu ekleriz ve orijinal b (b + 1) elemanları yayarız. Böylece her bir u0,, ub 82

83 bloğu tam olarak b eleman içerir. u0 bloğu şimdi tam olarak b eleman içermektedir ve bu nedenle eleman eklenebilir. ekle (i, x) işleminin çalışma zamanı yukarıda ortaya konan üç durumdan hangisine bağlı olduğuna göre değişir. 1. ve 2. durumlarda elemanları incelemek ve değiştirmek için en çok b blok kullanılır, bu nedenle O(b) zamanda çalışır. 3. durumda yayıl(u) yöntemi çağrıldığında b (b + 1) eleman yer değiştirir ve O(b2) zamanda çalışır. 3.durumun maliyeti görmezden gelinerek (daha sonra amortizasyon hesabıyla ele alınacaktır) i endeksinin yerini belirlemek ve x elemanını eklemek için gereken toplam zaman O(b + min { i, n i } / b ) olur. 83

84 3.3.4 Elemanların Silinmesi Bir AVListe den eleman silinmesi eklemeye benzerdir. i endeksini içeren u düğümünün yerini bulduktan sonra, u düğümüne ait bloğun b 1 elemandan daha azına sahip olduğu için bir elemanı u düğümünden silmenin olanaksız olduğu durum için hazırlıklı olunmalıdır. Yine, u0, u1, u2,... düğümlerinin işaretçilerini u, u.next, u.next.next olarak belirleyelim. u0 bloğunun boyutunun en azından b 1 olması için u0, u1, u2, düğümlerinden herhangi biri bize bir eleman ödünç vermelidir. Bunu araştırırken üç durum oluşabilir (bkz. Şekil 3.5): 1. Hızlıca ( r + 1 b adımda) bloğu b 1 elemandan daha fazla eleman içeren bir düğüm buluruz. Bu durumda, bir bloktan öncekine r eleman yer değiştirir. Böylece ur düğümünün ekstra blok elemanı u0 düğümünün ekstra blok elemanı haline gelir. Bunu takiben u0 bloğundan istenen eleman silinir. 2. Hızlıca ( r + 1 b adımda) bulduğumuz blok listelerinin sonuna geliriz. Bu durumda, ur düğümüne ait blok son bloktur ve ur düğümüne ait bloğunun en az n 1 eleman içermesine gerek yoktur. Bu nedenle, biz, yukarıdaki gibi devam etmeliyiz ve u0 düğümünün ekstra elemanı yapmak için ur düğümünden bir elemanı ödünç almalıyız. Bu ödünç alma sonrasında ur düğümünün bloğu boş hale gelirse, listeden silinir. 84

85 3. b adım sonrasında en fazla b-1 eleman içeren herhangi bir blok bulamadığımız takdirde u0,..., ub-1 her biri b-1 eleman içeren b adet dizi bloğu olmuştur. Tüm bu b(b-1) elemanı b-1 adet bloğun her birinde tam olarak b eleman olacak şekilde, u0,..., ub-2 düğüm halinde yeniden yapılandırırız ve şimdi boş olan, ub-1 düğümünü sileriz. u0 bloğu şimdi b eleman içermektedir ve bu nedenle eleman silinebilir. ekle(i, x) işlemine benzer şekilde sil(i) işleminin çalışma zamanı 3.durumdaki birarayagetir (u) yönteminin maliyeti görmezden gelinirse O(b + min { i, n i } / b ) olur. 85

86 3.3.5 yayıl (u) ve birarayagetir (u) Yöntemlerinin Amortize Edilmiş Analizi Şimdi, ekle (i, x) ve sil (i) işlemleri tarafından çağrılabilen yayıl (u) ve birarayagetir (u) yöntemlerinin maliyetini düşünüyoruz. Bütünlüğü sağlamak adına bunlar aşağıda verilmiştir: Bu yöntemlerin her birinin çalışma süresi iki iç içe döngü tarafından kısıtlanmıştır. Hem iç ve hem de dış döngüler, en fazla b + 1 defa çalışır, bu nedenle, bu yöntemlerin her birinin toplam çalışma süresi O((b+1)2) = O(b2) olur. Ancak, aşağıdaki önerme bu yöntemlerin ekle(i, x) ve sil (i) yöntemlerine yapılan her b nci çağrıda bir defa çalıştırıldığını gösterir. 86

87 Önerme 3.1. Boş bir AVListe oluşturulursa, ve ekle(i, x) ve sil (i) yöntemlerine m 1 defa çağrı yapılırsa, o zaman yayıl () ve birarayagetir () yöntemlerine yapılan tüm çağrılar sırasında harcanan toplam zaman O(bm) olur. Kanıt. Burada yine bize güç vaat eden amortize analiz yöntemini kullanacağız. Bir u düğümüne ait blok b eleman içermiyorsa düğümün kırılgan olduğu söylenir (öyle ki u ya son düğümdür, ya da bloğunda b 1 ya da b + 1 eleman vardır.) Bloğunda b eleman içeren herhangi bir düğümün engebeli olduğu söylenir. Burada biz sadece ekle (i, x) işlemini ve yayıl (u) yöntemine yaptığı çağrı sayısı ile olan ilişkisini dikkate alacağız. sil (i) ve birarayagetir (u) yöntemlerinin analizi benzerdir. Bir AVListe nin potansiyeli içerdiği kırılgan düğümlerin sayısı olarak tanımlanır. ekle(i, x) çalıştığında 1.durum oluştuğunda, sadece bir ur düğümünün boyutu değişmiştir. Bu nedenle, en fazla bir ur düğümü engebeli olmaktan çıkar, kırılgan olmaya geçer. 2.durum oluştuğunda, yeni bir düğüm oluşturulur ve bu düğüm kırılgandır ancak başka hiçbir düğüm boyut değiştirmez. Bu nedenle kırılgan düğümlerin sayısı bir artar. Böylece, 1. veya 2. durumlarda AVListe nin potansiyeli en fazla bir artar. Son olarak, 3.durum oluştuğunda, bunun nedeni u0,..., ub-1 düğümlerinin hepsinin kırılgan olmasıdır. Bunu takiben yayıl () çağrılır ve bu b kırılgan düğüm b + 1 engebeli düğüm ile yer değişir. Son olarak, x elemanı u0 bloğuna eklenir, ve u0 kırılgan hale gelir. Toplam olarak potansiyel b-1 kadar düşer. Özet olarak, potansiyelin başlangıç değeri 0 olur (listede hiçbir düğüm yoktur). 1.durum veya 2.durum her oluştuğunda potansiyel en çok 1 artar. 3.durum oluştuğunda potansiyel b - 1 azalır. (Kırılgan düğüm sayısı olan) potansiyel hiçbir zaman 0'dan az değildir. Şu sonuca varabiliriz ki, 3.durum her oluştuğunda 1.durum veya 2.durum en az b - 1 defa oluşmuştur. Böylece, yayıl (u) yöntemine yapılan her çağrı için ekle (i, x) yöntemine en azından b çağrı yapılmıştır. Bu kanıtı tamamlar. 87

88 3.3.6 Özet Aşağıdaki teorem AVListe veri yapısının performansını özetler: Teorem 3.3. AVListe Liste arayüzünü uygular. yayıl (u) ve birarayagetir (u) çağrılarının maliyetini dikkate almayarak, blok boyutu b olan bir AVListe işlem başına O(1 + min { i, n i } / b ) zamanda çalışan al (i) ve belirle (i, x); ve işlem başına O(b + min { i, n i } / b ) zamanda çalışan ekle (i, x) ve sil (i) işlemlerini destekler. Bundan başka, boş bir AVListe ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm yayıl (u) ve birarayagetir (u) çağrıları için gerekli toplam çalışma süresi O(bm) olur. n elemanlı bir AVListe nin kullandığı alan miktarı6 n + O(b + n / b) olarak ifade edilir. AVListe nin gerçekleştirimi Dizi Liste ve ÇBListe arasında seçim yapmayı gerektiriyor. Blok büyüklüğü b göz önünde tutularak bu iki yapıdan biri göreceli olarak seçilmelidir. En uç noktada b=2 iken, her AVListe düğümü en çok üç değer depolar. ÇBListe de hemen hemen aynıdır. Diğer bir uçta b > n iken, Dizi Liste de olduğu gibi tüm elemanlar sadece bir dizide saklanabilir. Bu iki uç arasında iseniz, bir liste elemanını eklemek veya kaldırmak için gereken zaman ile belirli bir liste elemanını bulmak için gereken zaman arasında bir seçim yapmanız gerekiyor. 3.4 Tartışma ve Alıştırmalar Tekli-bağlantılı ve çoklu-bağlantılı listelerin her ikisi de 40 yıldan bu yana programlarda kullanılmış olan ve kabul edilmiş tekniklerdir. Bunlar örneğin Knuth tarafından tartışılmıştır [46, Bölüm ]. AVListe veri yapıları için iyi bilinen bir alıştırma gibi görünüyor. Hatta AVListe döngüsüz bağlantılı liste olarak adlandırılabilir [69]. 6 Belleğin nasıl ölçüldüğünü Bölüm 1.4 teki tartışmadan hatırlayın. 88

89 Bir çift-bağlantılı listede alan tasarrufu yapmanın bir başka yolu XOR-listelerini kullanmaktır. XOR listesinde, her u düğümü, u.önceki ve u.sonraki ni bit-bit x-veya işlemine tabi tutan bir u.sonrakiönceki adında işaretçi ile gösterilir. Listenin kendisi dummy, ve (ilk düğüme, ya da liste boşsa dummy e eşit olan) dummy.sonraki olmak üzere iki işaretçi saklar. Bu teknik u ve u.önceki işaretçilerini kullanarak u.sonraki = u.önceki ^u.sonrakiönceki formülüyle u.sonraki değerinin hesaplanabileceğini bize anlatır. (Burada ^ işleci iki argümanının bit-bit x-veya hesabını yapmakta kullanılmıştır.) Bu teknik kodu biraz zorlaştırır, ve Java dahil çöp toplayan bazı dillerde bu tekniği uygulamak mümkün değildir, ancak düğüm başına yalnızca bir işaretçi gerektiren bir çifte-bağlantılı liste uygulamasını bize sunmaktadır. XOR-listelerinin ayrıntılı bir tartışması için bkz. Sinha nın dergi makalesi [70]. Alıştırma 3.1. Bir TBListe de yığ (x), yığıttan kaldır (), ekle (x) ve sil () işlemlerinde ortaya çıkabilecek tüm özel durumları önlemek için bir dummy düğüm kullanılması neden mümkün olmaz? Alıştırma 3.2. TBListe nin sondan ikinci elemanını döndüren sondanikinci () yöntemini liste eleman sayısını saklayan n değişkeni olmadan tasarlayın ve uygulayın. Alıştırma 3.3. al (i), belirle (i, x), ekle (i, x) ve sil (i) Liste yöntemlerini TBListe işlemlerine uygulayın. Bu işlemlerin her biri O(1 + i) zamanda çalışmalıdır. Alıştırma 3.4. TBListe nin tüm elemanlarını ters yönde sıralayan terssırala () yöntemini tasarlayın ve uygulayın. Bu yöntem O(n) zamanda çalışmalıdır, özyineleme, herhangi bir ikincil veri yapısını kullanması ve yeni düğümleri oluşturması istenmiyor. Alıştırma 3.5. boyutkontrol() adında birer TBListe ve ÇBListe yöntemini tasarlayın ve uygulayın. Bu yöntemler liste elemanları üzerinden adım adım giderek listede kayıtlı bulunan 89

90 n değeri ile eşleşip eşleşmediğini düğüm sayısını sayarak bulurlar. Bu yöntemlerin dönüş değerleri yoktur, ancak hesapladıkları boyut n değeri ile eşleşmiyorsa bir istisna fırlatırlar. Alıştırma 3.6. önceyeekle () yönteminin kodunu bir u düğümü oluşturarak w düğümünden hemen önce ÇBListe ye ekleyecek şekilde yeniden oluşturmayı deneyin. Bu bölümden alıntı yapmayın. Kodunuz tam olarak bu kitapta verilen kod ile eşleşmiyor olabilir. Bu kodun doğru olmadığı anlamına gelmez. Çalışıp çalışmadığını test ederek görün. Bundan sonraki birkaç alıştırma ÇBListe üzerinde yapılabilecek değişiklikleri içeriyor. Herhangi bir yeni düğüm veya geçici dizi tahsis etmeden bunları tamamlamanız gerekiyor. Sadece mevcut düğümlerin önceki ve sonraki değerlerini değiştirerek bunları yapabilirsiniz. Alıştırma 3.7. Liste bir palindrom olduğunda doğru döndüren palindromu () adında bir ÇBListe yöntemi yazın, yani her i {0,, n 1} için i pozisyonundaki eleman n i 1 pozisyonundaki elemana eşittir. Kodunuz O(n) zamanda çalışmalıdır. Alıştırma 3.8. ÇBListe elemanlarının yerlerini dönüştürerek değiştirecek bir elemanyerdönüştür (r) yöntemini i pozisyonundaki bir liste elemanının yeri (i + r) mod n pozisyonunda olacak şekilde gerçekleştirin. Bu yöntemin çalışma zamanı O(1+min {r, n r}) olmalıdır. Alıştırma 3.9. Bir ÇBListe nin i pozisyonunda liste içeriğini kısaltan içeriğikısalt (i) adında bir yöntem yazın. Bu yöntemi çalıştırdıktan sonra listenin boyutu i olacak şekilde belirlenmeli ve sadece 0,, i - 1 endekslerindeki elemanları içermelidir. Dönüş değeri i,, n 1 endekslerindeki elemanları içeren başka bir ÇBListe dir. Bu yöntemin çalışma zamanı O(min {i, n i}) olmalıdır. Alıştırma l2 argümanında bir ÇBListe alan, bu listeyi boşaltarak içeriğini onu çağıran listeye, sırasıyla, ekleyen em(l2) adında bir ÇBListe yöntemini yazın. Örneğin, l1 elemanları a, b, c ve l2 elemanları d, e, f olduğu takdirde, l1.em (l2) çağrıldıktan sonra l1 içeriği a, b, c, d, e, f ve l2 içeriği boş olur. Alıştırma ÇBListe den tüm tek sayılı endekslere ait olan elemanları ortadan kaldıran ve bu elemanları içeren bir ÇBListe döndüren tekliendekselemanları () adında bir ÇBListe 90

91 yöntemi yazın. Örneğin, l1 elemanları a, b, c, d, e, f olduğu takdirde, l1.tekliendekselemanları () çağrıldıktan sonra l1 elemanları a, c, e olmalı ve dönüş değeri olarak elemanları b, d, f olan bir liste dönmelidir. Alıştırma ÇBListe nin elemanlarını ters sırada yeniden yapılandıran bir ters () yöntemi yazın. Alıştırma Bu alıştırma Bölüm de tartışıldığı gibi bir ÇBListe sıralamasını gerçekleştirmek için size birleştirme-sıralama algoritmasının bir uygulamasını tanıtıyor. Uygulamanızda, elemanlar arasında karşılaştırmalar yapmak için karşılaştır (x) yöntemini kullanın, böylece ortaya çıkan uygulama ile Karşılaştırılabilir arayüzünü uygulayan elemanları içeren herhangi ÇBListe yi sıralayabilirsiniz. 1. ilkiseç (l2) adında bir ÇBList yöntemi yazın. Bu yöntem, l2 listesinden birinci düğümü alır ve alıcı listesine ekler. Yeni bir düğüm oluşturmak gerektiği dışında bu ekle (boyut (), l2.sil (0)) çağrısının eşdeğeridir. 2. l1 ve l2 sıralı listelerini alan, onları birleştiren, ve sıralı yeni listeyi döndüren birleştir(l1, l2) adında bir ÇBListe statik yöntemi yazın. Bu süreç sonunda l1 ve l2 listelerinin içeriği boş hale gelir. Örneğin l1 elemanları a, c, d ve l2 elemanları b, e, f olduğu takdirde, bu yöntem a, b, c, d, e, f içeren yeni bir liste döndürür. 1. Listede yer alan elemanları birleştirme-sıralama algoritmasını kullanarak sıralayan sırala () yöntemi yazın. Bu özyinelemeli algoritma şu şekilde çalışır: a) Liste içeriği 0 veya 1 eleman ise o zaman yapacak bir şey yoktur. Diğer durumlarda, b) içeriğikısalt (boyut() / 2) yöntemini kullanarak listeyi yaklaşık olarak eşit uzunlukta olan iki listeye l1, l2 bölün. c) Özyinelemeli olarak l1 listesini sıralayın. d) Özyinelemeli olarak l2 listesini sıralayın, en sonunda e) l1, l2 listelerini tek sıralı liste haline birleştirin. Sonraki birkaç alıştırma daha zordur ve bir Yığıt ta saklanan minimum değer ile elemanlar Kuyruk a eklendikçe ve silindikçe ne olduğuna dair net bir anlayış gerektirir. 91

92 Alıştırma yığ (x), yığıttan kaldır (), ekle (x) ve sil () ve bunun yanı sıra şu anda veri yapısında depolanan en düşük değeri veren min () işlemini destekleyen ve kıyaslanabilir elemanları saklayabilen bir MinYığıt veri yapısını tasarlayın ve uygulayın. Tüm işlemler sabit zamanda çalışacaktır. Alıştırma ekle (x), sil (), boyut () ve bunun yanı sıra şu anda veri yapısında depolanan en düşük değeri veren min (x) işlemlerini destekleyen ve kıyaslanabilir elemanları saklayabilen bir MinKuyruk veri yapısını tasarlayın ve uygulayın. Tüm işlemler sabit amortize zamanda çalışmalıdır. Alıştırma ekleilk (x), ekleson (x), sililk (), silson (), boyut () ve bunun yanı sıra şu anda veri yapısında depolanan en düşük değeri veren min () işlemlerini destekleyen ve kıyaslanabilir elemanları saklayabilen bir MinİkiBaşlıKuyruk veri yapısını tasarlayın ve uygulayın. Tüm işlemler sabit amortize zamanda çalışmalıdır. Sonraki alıştırmalar okuyucunun alan-verimli AVListe nin uygulanması ve analizi hakkında anlayışını test etmek için hazırlanmıştır. Alıştırma Bir AVListe bir Yığıt gibi kullanılırsa, (böylelikle AVListe ye tek değişiklik yığ(x) = ekle (boyut(), x) ve yığıttan kaldır() = sil (size() 1) kullanılarak yapılırsa) bu işlemler b değerinden bağımsız olarak, sabit amortize zamanda çalışır. Alıştırma Tüm İki Başlı Kuyruk işlemlerini işlem başına b değerinden bağımsız olarak sabit amortize zamanda destekleyen bir AVListe versiyonunu tasarlayın ve uygulayın. Alıştırma Üçüncü bir değişken kullanmadan iki int değişken değerlerinin bit-bit-veya işleci, ^, kullanılarak nasıl değiş-tokuş edileceğini açıklayın. 92

93 Bölüm 4 Sekme Listeleri Bu bölümde, çeşitli uygulamaları olan güzel bir veri yapısını tartışacağız: sekme listeleri. Sekme listesinin Liste arayüzü uygulaması al(i), belirle(i, x), ekle(i, x), ve sil(i) işlemlerini O(log n) zamanda gerçekleştirir. Ayrıca Sıralı Küme gerçekleştirimi tüm işlemleri O(log n) beklenen zamanda çalıştırır. Sekme listelerinin etkinliği dayandığı rasgelelikten kaynaklanır. Yeni bir elemanı sekme listesine eklerken, elemanın yüksekliğini belirlemek için rasgele yazı-tura atılır. Sekme listelerinin performansı beklenen çalışma süreleri ve yol uzunlukları cinsinden ifade edilir. Beklenti, sekme listesi tarafından kullanılan rasgele yazı-tura atma üzerinden üstlenilir. Rasgele yazı-tura atma yarı-rasgele sayı (ya da bit) üreteci kullanılarak gerçekleştirilir. 4.1 Temel Yapı Kavramsal olarak, sekme listesi L0,, Lh tekli-bağlantılı listelerinden oluşan bir dizidir. Her Lr listesi Lr-1 listesinin içindeki elemanların bir alt kümesini içerir. n eleman içeren giriş listesi L0 ile başlarız. Bunu takiben L1 listesini L0 elemanlarından, L2 listesini L1 elemanlarından, ve buna benzer şekilde diğer listeleri oluştururuz. Lr listesinin elemanlarını oluştururken Lr-1 listesinde bulunan her x elemanı için yazı-tura atılır. Yazı gelirse x dahil edilir. Boş bir Lr listesi ile karşılaşıldığında süreç sonlanır. Örnek bir sekme listesi Şekil 4.1 'de gösterilmiştir. 93

94 Sekme listesinin içinde yer alan bir x elemanının yüksekliği bu elemanın bulunduğu bir Lr listesinin en büyük r değeri ile ölçülür. Buna göre, örneğin, sadece L0 da görünen elemanlar 0 yüksekliğe sahiptir. Birkaç dakikamızı bu konuda düşünmeye ayırırsak, x'in yüksekliği aşağıdaki deney ile belirlenir: Tura gelene kadar art arda yazı-tura atın. Kaç kere yazı geldi? Cevap, şaşırtıcı olmayacağı üzere, bir düğümün beklenen yüksekliği 1'dir. (Tura gelmeden önce iki kez yazı-tura atmayı bekliyoruz, ancak son atışı saymıyoruz.) Bir sekme listesinin yüksekliği en yüksek düğümünün yüksekliğidir. Her listenin başında, bu liste için bir dummy düğüm gibi davranan ve başlangıç olarak adlandırılan özel bir düğüm vardır. Sekme listelerinin anahtar özelliği Lh listesinin başlangıcından L0 listesindeki tüm düğümlere arama yolu olarak adlandırılan kısa bir yol olmasıdır. Bir u düğümü için bir arama yolunun nasıl düzenleneceğini hatırlamak kolaydır (bkz. Şekil 4.2) : Sekme listesinin sol üst köşesinden (Lh listesinin başlangıcı) başlayın ve u düğümünü aşmadığınız sürece her zaman sağa doğru gidin. Aşağıdaki listeye inip getirmeniz için her seferinde aşağı yönde bir adım atmanız gerekir. Daha kesin bir ifadeyle, L0 listesi içindeki u düğümüne bir arama yolunu oluşturmak için Lh listesinin w başlangıcından yola çıkarız. Sonra w.next incelenir. Eğer w.next içinde L0 içindeki u düğümünden önce görünen bir eleman varsa o zaman w = w.next olarak belirlenir. Aksi takdirde, bir alt listeye geçilir ve Lh-1 listesinin w yerinden aramaya devam ederiz. L0 içindeki u düğümünün bir öncesine ulaşıncaya kadar bu şekilde devam ediyoruz. Bölüm 4.4 te ispat edeceğimiz aşağıdaki sonuç arama yolunun oldukça kısa olduğunu göstermektedir: Önerme 4.1. L0 içindeki herhangi bir u düğümü için arama yolunun beklenen uzunluğu en fazla 2 log n + O(1) = O(log n) olur. Bir sekme listesini gerçekleştirmenin alan-verimli bir yolu veri değeri, x, ve bir işaretçi dizisi olan sonraki ne sahip u düğümlerini tanımlamaktır. u.sonraki[i] L1 listesi içinde u düğümünden sonra gelene işaret etmelidir. Böylece, bir düğümdeki x verisi birden fazla listede yer alsa bile x sadece bir başvuruyla depolanır. 94

95 Sonraki iki bölüm sekme listelerinin iki farklı uygulamasını tartışıyor. Bu uygulamaların her birinde L0 ana yapıyı saklar (bir eleman listesi veya sıralı bir küme eleman). Bu yapılar arasındaki temel fark, bir arama yolu üzerinden nasıl yol alındığıdır; özellikle Lr-1 e inileceği mi, yoksa Lr içinde sağa doğru mu gidileceği konusunda karar vermede ayrılık gösterirler. 4.2 Sıralı Küme Sekme Listesi : Verimli bir Sıralı Küme Sıralı Küme Sekme Listesi, Sekme Listesi yapısını kullanarak Sıralı Küme arayüzünü gerçekleştirir. Bu şekilde kullanıldığında, L0 listesi Sıralı Küme elemanlarını sıralı bir şekilde depolamaya yarar. bul (x) yöntemi y x olan en küçük y değeri için arama yolunu izleyerek çalışır. 95

96 y için arama yolunu izlemek kolaydır: Lr içinde bir u düğümüne rastladığımızda sağdaki u.next[r].x verisine dikkat ederiz. Eğer x > u.next[r].x ise, Lr içinde sağa doğru bir adım atarız; aksi takdirde, Lr-1 yönünde aşağı doğru hareket ederiz. Bu arama sırasında atılan her adım (sağa veya aşağı doğru) sadece sabit zaman alır; böylece, Önerme 4.1 ile, bul (x) yönteminin beklenen çalışma süresi O(log n) olur. Bir eleman eklemeden önce yeni bir düğümün yüksekliği olan, k, Sıralı Küme Sekme Listesi tarafından hesaplanmalıdır. Bu amaçla yazı-tura atmak için bir yöntem bulunmalıdır. Bir rasgele tamsayı, z, seçerek bunu yapabiliriz. Bunun için, ikili moddaki z sayısının sonda gelen 1 leri sayılır:7 Bir Sıralı Küme Sekme Listesi içinde ekle (x) yöntemini gerçekleştirmek için önce x aranır ve yükseklikseç () yöntemi kullanılarak k belirlenir. Bunu takiben L0,..., Lk listeleri x için uç uça birbirine bağlanır. Bunu yapmanın en kolay yolu, arama yolunun Lr listesinden Lr-1 listesine indiği düğümlerin izlerini kaydeden bir Dizi Yığıt kullanmaktır. Daha kesin bir ifadeyle yığıt[r] arama yolunun Lr-1 listesine indiği Lr düğümüdür. x eklenirken değiştirilen düğümler, tam olarak, yığıt[0] yığıt[k] tarafından kaydedilir. ekle (x) algoritması aşağıda gösterilmiştir: 7 Bu yöntem tam olarak yazı-tura atma deneyinin bir kopyası değildir, çünkü k değeri her zaman int bit sayısından daha az olacaktır. Bununla birlikte, yapı 232= sayısından daha fazla eleman içermediği sürece bu önemsiz bir etkiye sahiptir. 96

97 x elemanını silmek benzer şekilde yapılır, ancak burada arama yolunu takip etmek için yığıt a gerek duyulmaz. Arama yolu takip edilirken aynı anda silme yapılabilir. x elemanını bulmak için yapılan arama sırasında bir u düğümünden aşağıya doğru yapılan her harekette u.next.x = x eşitliği kontrol edilir; sağlanması durumunda u bir sonraki düğüme listenin dışına doğru uç uça bağlanır. 97

98 Özet Aşağıdaki teorem Sıralı Küme kullanılarak gerçekleştirilen Sekme Listesi nin performansını özetler: Teorem 4.1. Sıralı Küme Sekme Listesi, Sıralı Küme arayüzünü uygular. Sıralı Küme Sekme Listesi işlem başına O(log n) beklenen zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. 98

99 4.3 Liste Sekme Listesi: Verimli Rasgele Erişim Listesi Liste Sekme Listesi bir Sekme Listesi yapısını kullanarak Liste arayüzünü uygular. Bir Liste Sekme Listesi nde L0 listesi Sekme Listesi nde olduğu elemanları listede göründükleri sırayla depolanır. Sıralı Küme gibi, elemanlar O(log n) zamanda eklenir, çıkarılır ve erişilebilir. Bunun mümkün olabilmesi için, i'nci elemana erişmek için gerekli arama yolunu takip etmemiz için bir yol bulmamız gerekir. Bunu yapmanın en kolay yolu herhangi bir Lr listesi için kenar uzunluğu kavramını tanımlamaktır. L0 içindeki her kenarın uzunluğu 1 olarak tanımlanır. r > 0 olacak şekilde Lr listesindeki, e, kenarının uzunluğu Lr-1 içindeki e kenarının altında yer alan uzunlukların toplamı olarak tanımlanmaktadır. Aynı anlama gelecek şekilde, e uzunluğu e altında yer alan L0 kenarlarının sayısıdır. Kenar uzunluklarının gösterildiği bir sekme listesi örneği için Şekil 4.5 'e bakınız. Sekme listelerinin kenarları dizilerde saklandığı için uzunlukları aynı şekilde saklanabilir. 99

100 Bu uzunluk tanımının kullanışlı bir özelliği, eğer şu anda L0 içinde j pozisyonunda yer alan düğümde bulunuyorsak, ve l uzunluğunda bir kenarı izliyorsak, L0 içinde j + l pozisyonundaki bir düğüme ulaşmamızdır. Bu şekilde, bir arama yolunu takip ederken, L0 içindeyken bulunduğumuz düğümün j pozisyonunu takip edebiliriz. Lr içindeki bir u düğümünde isek, j + u.next[r] kenarının uzunluğu i den küçükse, sağa doğru gideriz. Aksi takdirde, Lr-1 içine aşağı doğru gideriz. al(i) ve belirle(i, x) işlemlerinin en zor kısmı L0 içindeki i nci düğümü bulmak olduğu için bu işlemler O(log n) zamanda çalışır. Liste Sekme Listesi Sekme Listesi nin içindeki i pozisyonuna bir eleman eklemek oldukça kolaydır. Sıralı Küme aksine, burada yeni bir düğümün muhakkak ekleneceğinden eminiz. Ekleme yeni düğümün konumunu ararken aynı zamanda gerçekleştirilebilir. Önce yeni eklenen w düğümünün yüksekliği olan k seçilir ve sonra i için arama yolu izlenir. Ne zaman 100

101 ki arama yolu r k olmak üzere Lr dan aşağı doğru giderse w için Lr uç uça birleştirilir. Sadece kenar uzunluklarının düzgün olarak güncellendiğinden emin olmak için özen göstermemiz gerekiyor. Bkz. Şekil 4.6. Unutmayın ki, Lr içindeki bir u düğümünden itibaren başlayan arama yolu ne zaman aşağı doğru giderse, u.next [r] kenar uzunluğu bir artırılır, çünkü i pozisyonundaki kenarın altına yeni bir eleman ekliyoruz. w düğümü için listelerin u ve z olarak uç uça birleştirilmesi Şekil 4.7 de gösterildiği gibi çalışır. Arama yolu takip edilirken L0 içindeki u düğümünün j pozisyonu takip edilmektedir. Bu nedenle, u düğümünden w düğümüne kenar uzunluğunun i j olduğunu biliyoruz. Bunun yanı sıra, aynı zamanda w düğümünden z düğümüne uzanan kenar uzunluğunu, u düğümünden z düğümüne kenar uzunluğu olan l ye bakarak çıkarsayabiliriz. Bu nedenle listeler w için uç uça birleştirilir ve kenar uzunlukları sabit zaman içinde güncellenir. 101

102 Kod oldukça basit olduğu için, bu anlatılanlar size olduğundan daha karmaşık gelmiş olabilir: 102

103 Artık, Liste Sekme Listesi nde sil (i) işleminin gerçekleştirimi açık hale geldi. Düğüm için i pozisyonundaki arama yolu izlenir. Arama yolu bir u düğümünden aşağı r seviyesinde her adım attığında, u aynı seviyede kalacak şekilde kenar uzunluğu azaltılır. Aynı zamanda u.next [r] değerinin i yi gösterdiği kontrol edilir, ve gösteriyorsa listeler o seviyede uç uça birleştirilir. Bir örnek Şekil 4.8 'de gösterilmiştir Özet Aşağıdaki teorem Liste Sekme Listesi veri yapısının performansını özetler: Teorem 4.2. Liste Sekme Listesi, Liste arayüzünü uygular. Liste Sekme Listesi işlem başına O(log n) beklenen zamanda çalışan al(i), belirle(i, x), ekle(i, x) ve sil(i) işlemlerini destekler. 103

104 4.4 Sekme Listelerinin Analizi Bu bölümde, bir Sekme Listesi içindeki arama yolunun beklenen yüksekliği, boyutu ve uzunluğunu analiz edeceğiz. Bu bölüm, temel olasılık konusunda bir miktar bilgi birikiminizin var olmasını gerektirir. Yazı-tura atma ile ilgili aşağıdaki gözlem çeşitli kanıtlamalar için bir temel oluşturmaktadır. Önerme 4.2. T adil bir paranın fırlatıldıktan sonra ilk defa yazı geldiği zamana kadar olan atma sayısı olsun. O zaman E[T] = 2 olur. Kanıt. İlk defa yazı geldiği zaman, yazı-tura atmayı durduğumuzu düşünelim. Gösterge değişkeni tanımlayın : Unutmayın ki, ancak ve ancak ilk i 1 yazı-tura sonucu yazı geldiği takdirde, Ii = 1 sağlanır, bu nedenle sayısı olur. Gözlemlemelisiniz ki, T, toplam yazı-tura atma ile verilir. Bu nedenle, Sonraki iki önerme, sekme listelerinin doğrusal boyutta olduğunu bize anlatıyor: 104

105 Önerme 4.3. n eleman içeren bir sekme listesinin başlangıç düğümleri dışında kalan beklenen düğüm sayısı 2n olur. Kanıt. Belirli bir x elemanının Lr listesi tarafından depolanma olasılığı 1 / 2r, bu nedenle Lr içindeki düğümlerin beklenen sayısı n / 2r olur.8 Böylece, tüm listelerde bulunan düğümlerin beklenen toplam sayısı Önerme 4.4. n eleman içeren bir sekme listesinin beklenen yüksekliği log n + 2 olur. Kanıt. Her r {1, 2, 3,, } için gösterge rasgele değişkenini aşağıdaki gibi tanımlayın: Sekme listesi yüksekliği, h, olarak verilir. Unutmayın ki, Ir değeri Lr uzunluğu olan Lr dan asla daha fazla olamaz, bu nedenle, olur. Aşağıdaki hesaplama kanıtı tamamlar: 8 Bunun gösterge değişkenleri ve beklentinin doğrusallığını kullanarak nasıl oluşturulduğunu görmek için bkz. Bölüm

106 Önerme 4.5. Tüm başlangıç düğümlerinin de içerildiği, n elemanı depolayan bir sekme listesinin beklenen düğüm sayısı, 2n + O(log n) olur. Kanıt. Önerme 4.3 ile belirtilmiştir ki, başlangıç düğümleri dışında kalan düğümlerin beklenen sayısı 2n olur. Başlangıç düğümlerin sayısı sekme listesinin yüksekliği olan, h, ile verilir. Böylece Önerme 4.4 ile belirtilmiştir ki, başlangıç düğümlerinin beklenen sayısı en fazla log n + 2 = O(log n) olur. Önerme 4.6. Bir sekme listesinin beklenen arama yolu uzunluğu en fazla 2 log n + O(1) olur. Kanıt. Bunu görmek için en kolay yol, bir x düğümü için ters arama yolunu ele almaktır. Bu yol L0 içindeki x düğümünden önce gelen düğümle başlar. Zamanla herhangi bir noktada, eğer yol bir seviye yukarı gidebilirse, gider. Bir seviye yukarı çıkamıyorsa o zaman sola doğru gider. Birkaç dakika için düşünülürse, bu ters arama yolunun, ters olması dışında x için arama yolu ile aynı olması konusunda ikna olunur. Belirli bir r seviyesinde, ters arama yolu tarafından ziyaret edilen düğümlerin sayısı aşağıdaki deney ile ilgilidir: Yazı-tura atın. Yazı gelirse, yukarı doğru gidin ve durun. Aksi takdirde, sola doğru hareket edin ve deneyi tekrarlayın. Yazı gelmeden önceki yazı-tura atma sayısı, bir 106

107 ters arama yolunun, belirli bir seviyede sola doğru attığı adımların sayısını temsil eder. 9 Önerme 4.2 ilk defa yazı gelmeden önceki beklenen yazı-tura atma sayısının 1 olduğunu bildirmiştir. r seviyesinde ileri yöndeki arama yolunun sağa doğru attığı adım sayısının Sr ile gösterildiğini düşünelim. Az önce tartışıldığı gibi, E[Sr] 1. Ayrıca, Lr içinde Lr uzunluğundan daha fazla adım atamayacağımıza göre Sr Lr, bu nedenle Böylece şimdi, Önerme 4.4. ün kanıtında olduğu gibi, bitirebiliriz. Sekme listesindeki bir u düğümü için arama yolunun uzunluğu S, ve sekme listesinin yüksekliği h olsun. Bu durumda, 9 Bu sayı sola doğru atılan adım sayısından fazla olabilir, çünkü deney ya ilk defa yazı geldiğinde veya arama yolu başlangıca ulaştığında hangisi önce gelirse bitirilmelidir. Bu bir sorun değildir, çünkü önerme sadece bir üst sınır ifade etmektedir. 107

108 Aşağıdaki teorem bu bölümdeki sonuçları özetlemektedir: Teorem 4.3. n eleman içeren bir sekme listesinin beklenen boyutu O(n) ve herhangi bir eleman için arama yolunun beklenen uzunluğu en fazla 2 log n + O(1) olur. 4.5 Tartışma ve Alıştırmalar Sekme listeleri Pugh [62] tarafından bir dizi uygulamaları ve uzantıları [61] da dahil olmak üzere tanıtılmıştır. O tarihten bu yana da yoğun çalışmalar yapılmıştır. Çeşitli araştırmacılar i nci eleman için arama yolunun beklenen uzunluğu ve değişkenleri üzerine çok hassas analizler yapmıştır [45, 44, 58]. Deterministik [53], taraflı [8, 26], ve kendini ayarlayan sekme listeleri [12] geliştirilmiştir. Sekme listeleri uygulamaları çeşitli diller ve çerçeveler için yazılmıştır ve açık kaynak veritabanı sistemlerinde kullanılmaktadır [71, 63]. Sekme listelerinin bir benzeri HP-UX işletim sistemi çekirdeğinin süreç yönetim yapılarında kullanılmaktadır [42]. Sekme listeleri aynı zamanda Java API 1.6 [55] sürümünün bir parçasıdır. Alıştırma 4.1. Şekil 4.1'deki sekme listesi üzerinde 2.5 ve 5.5 elemanları için arama yollarını gösterin. Alıştırma 4.2. Şekil 4.1'deki sekme listesi üzerinde 0.5 (1 yüksekliğe sahip) ve 3.5 (2 yüksekliğe sahip) değerlerinin toplamasını gösterin. Alıştırma 4.3. Şekil 4.1'deki sekme listesi üzerinde 1 ve 3 değerlerinin silinmesini gösterin. Alıştırma 4.4. Şekil 4.5 deki Liste Sekme Listesi üzerinde sil(2) işleminin çalıştırılmasını gösterin. Alıştırma 4.5. Şekil 4.5 deki Liste Sekme Listesi üzerinde ekle(3, x) işleminin çalıştırılmasını gösterin. Varsayın ki, yeni oluşturulan düğüm için yükseklikseç () fonksiyonu yükseklik değeri olarak 4 seçsin. 108

109 Alıştırma 4.6. ekle(x) ve sil(x) işlemleri sırasında bir Liste Sekme Listesi içindeki değişen işaretçilerin beklenen sayısının sabit olduğunu gösterin. Alıştırma 4.7. Diyelim ki, bir elemanı yazı-tura atışımızın sonucuna göre Li-1 listesinden Li listesine geçirmek yerine, bunu 0 < p < 1 olan p olasılığı ile gerçekleştiriyoruz. 1. Bu değişiklik ile, bir arama yolunun beklenen uzunluğunun en fazla olduğunu gösterin. 2. Önceki ifadeyi minimize eden p değeri nedir? 3. Sekme listesinin beklenen yüksekliği nedir? 4. Sekme listesinin beklenen düğüm sayısı nedir? Alıştırma 4.8. Sıralı Küme Sekme Listesi bul(x) yöntemi bazen gereksiz karşılaştırmalar gerçekleştirir; x aynı değerle kıyaslandığında bunlar oluşabilir. Bir u düğümü için u.next [r] = u.next [r - 1] olduğunda bunlar oluşur. Bu gereksiz karşılaştırmaların nasıl oluştuğunu gösterin, ve oluşmalarını engellemek için bul(x) gerçekleştiriminde değişiklikler yapın. Değiştirilmiş bul(x) yöntemi tarafından yapılan karşılaştırmaların beklenen sayısını analiz edin. Alıştırma 4.9. Sıralı Küme arayüzünü uygulayan, ama aynı zamanda derecesine göre elemanlara hızlı erişim sağlayan bir sekme listesi versiyonunu tasarlayın ve uygulayın. Bu yapı i dereceli elemanı döndüren al (i) fonksiyonunu O(log n) beklenen zamanda çalıştırmalıdır. (Sıralı Küme de yer alan bir x elemanının derecesi x değerinin altındaki eleman sayısıdır.) Alıştırma Bir sekme listesinde parmak, arama yolunun indiği arama yolu üzerindeki düğüm sırasını depolayan bir dizi olarak tanımlanır. (91. sayfadaki ekle (x) kodundaki yığıt değişkeni bir parmaktır; Şekil 4.3 'deki kırmızı ile boyalı düğümler parmak içeriğini göstermektedir.) Bir parmağın en alttaki, L0 listesindeki bir düğüme ait arama yoluna işaret ettiğini düşünebilirsiniz. Bir parmak araması, u.x < x ve (u.next = null veya u.next.x > x) olan bir u düğümüne ulaşana kadar listeden yukarı doğru yürüyerek parmağı kullanır, ve sonra u düğümünden başlayarak x için normal bir arama yaparak bul (x) işlemini uygular. L0 içinde depolanan x ve 109

110 parmak ile işaret edilen değer arasındaki sayı değerleri r ise, bir parmak araması için gerekli adımların beklenen sayısının O(1 + log r) olduğunu kanıtlamak mümkündür. Sekme Listesi nin bir alt sınıfı olan ve içsel bir parmak kullanarak bul (x) işlemini uygulayan Parmak İle Sekme Listesi ni gerçekleştirin. Bu alt sınıf, daha sonra her bul (x) işlemini bir parmak araması olarak gerçekleştiren bir parmak depolar. Her bul (x) işlemi sırasında başlangıç noktası olarak, önceki bul (x) işleminin sonucuna işaret eden bir parmak kullanılacak şekilde parmak güncelleştirilmesi yapılır. Alıştırma Bir Liste Sekme Listesi nin i pozisyonunda liste içeriğini kısaltan içeriğikısalt (i) adında bir yöntem yazın. Bu yöntemi çalıştırdıktan sonra listenin boyutu i olacak şekilde belirlenmeli ve sadece 0,, i - 1 endekslerindeki elemanları içermelidir. Dönüş değeri i,, n 1 endekslerindeki elemanları içeren başka bir Liste Sekme Listesi dir. Bu yöntemin çalışma zamanı O(log n) olmalıdır. Alıştırma l2 argümanında bir Liste Sekme Listesi alan, bu listeyi boşaltarak içeriğini onu çağıran listeye, sırasıyla, ekleyen em(l2) adında bir Liste Sekme Listesi yöntemini yazın. Örneğin, l1 elemanları a, b, c ve l2 elemanları d, e, f olduğu takdirde, l1.em (l2) çağrıldıktan sonra l1 içeriği a, b, c, d, e, f ve l2 içeriği boş olur. Bu yöntemin çalışma zamanı O(log n) olmalıdır. Alıştırma Temel yapı olarak bir Sıralı Küme kullanarak (büyük) bir metin dosyasını okuyan ve metinde yer alan herhangi bir alt dize için, etkileşimli, arama yapmanızı sağlayan bir uygulama tasarlayın ve uygulayın. Kullanıcı sorgusunu yazdıkça eş metnin parçası, eğer varsa, sonuçta görünmelidir. İpucu 1: Her altdize bazı sonek in önekidir. Bu nedenle metin dosyasının tüm sonek lerini saklamak yeterlidir. İpucu 2: Herhangi bir sonek, kısa ve etkili bir şekilde, ek in metinde nerede başladığını gösteren bir tamsayı ile tek olarak temsil edilebilir. 110

111 Gutenberg Projesinde [1] mevcut kitaplardan bazılarında yer alan büyük metinler üzerinde uygulamanızı test edin. Eğer doğru uygulanırsa, tuş vuruşlarını yazarken sonuçları görmek arasında hiçbir gecikme olmayacak şekilde uygulamanız çabuk çalışacaktır. Alıştırma (Bu alıştırma Bölüm 6.2 deki ikili arama ağaçları konusu okunduktan sonra yapılmalıdır.) İkili arama ağaçları ile sekme listelerini aşağıdaki şekillerde karşılaştırın: 1. Bir sekme listesinin bazı kenarları silindiğinde, ikili ağaç gibi görünen ve ikili bir arama ağacına benzer bir yapıya bizi nasıl götürdüğünü açıklayın. 2. Sekme listeleri ve ikili arama ağaçlarının her ikisi de yaklaşık aynı sayıda (düğüm başına 2) işaretçi kullanıyor. Oysa ki, sekme listeleri bu işaretçilerden daha iyi yararlanmaktadır. Neden? Açıklayın. 111

112 Bölüm 5 Karma Tabloları Karma tabloları geniş bir küme olan U = {0,, 2w - 1 } elemanlarından oluşan küçük sayıda bir n tamsayıyı depolamanın etkili bir yöntemidir. Karma tablosu terimi geniş bir yelpazedeki veri yapılarını içerir. Bu bölümde karma tabloların en yaygın uygulamalarından biri olan zincirleme aracılığıyla karma yöntemi üzerinde duruluyor. Çok sıklıkla karma tabloları tamsayı olmayan veri türlerini depolar. Bu durumda, bir tamsayı karma kodu, her veri elemanı ile ilişkilendirilir ve karma tabloda kullanılır. Bu bölümün ikinci kısmı böyle karma kodların nasıl hesaplandığını anlatıyor. Bu bölümde kullanılan bazı yöntemler, belirli bazı aralıklarda rasgele tamsayılar arasından seçim yapmamızı gerektirir. Verilen kod örneklerinde, bu "rasgele" tamsayılardan bazıları kodlanmış sabitlerdir. Bu sabitler atmosferik gürültüden üretilen rasgele bitler kullanılarak elde edilmiştir Zincirleme Karma Tablo: Zincirleme Aracılığıyla Adresleme Zincirleme Karma Tablo veri yapısı zincirleme aracılığıyla karma yöntemini kullanarak verilerin toplamını bir, t, liste dizisi halinde depolar. Bir tamsayı, n, tüm listelerdeki toplam eleman sayısından sorumludur (bkz. Şekil 5.1): hash(x) ile belirtilen bir x veri elemanının karma değeri, {0,, t.uzunluk - 1} aralığında bir değerdir. i karma değerine sahip tüm elemanlar listede t[i] pozisyonunda saklanmaktadır. 112

113 Listelerin çok uzun olmadığından emin olmak için şu değişmez sağlanır: Böylece bu listelerden birinde depolanan elemanların ortalama sayısı n/t.uzunluk 1 olur. Karma tabloya, bir x elemanı, eklemek için önce t uzunluğunun artırılması gerektiği kontrol edilir, gerekiyorsa artırılır. x karma kodu {0,, t.uzunluk 1} aralığında bir i tamsayısı ise, x t[i] listesine eklenir. Gerekirse, tablonun büyültülmesi, t uzunluğunu iki katına çıkarmayı ve yeni tabloya tüm elemanların yeniden eklenmesini içerir. Bu strateji Dizi Yığıt uygulamasında kullanılan strateji ile birebir örtüşür. Sonuç aynıdır: Bir dizi veriyi eklemenin amortize büyüme maliyeti sadece sabit bir sayıdır (bkz. Önerme 2.1, Sayfa 33). Büyültmenin yanı sıra, Zincirleme Karma Tablo ya yeni bir x değeri eklerken yapılan diğer çalışma sadece t[hash(x)] listesine x eklemeyi içerir. Bölüm 2 veya 3 'de anlatılan Liste uygulamalarının herhangi biri için bu sadece sabit zaman alır. 113

114 Karma tablodan, bir x elemanını, silmek için önce t[hash(x)] listesi üzerinde ilerleyerek x elemanı bulunur, sonra silinir. Bu O(nhash(x)) zaman alır, ni burada t[i] listesinde depolanmış listenin uzunluğunu ifade ediyor. Karma bir tabloda x elemanının aranması benzerdir. t[hash(x)] listesi içinde doğrusal bir arama gerçekleştiririz: Yine bu, t[hash(x)] listesinin uzunluğu ile orantılı zaman alır. Bir karma tablosunun performansı kritik olarak hash fonksiyonunun seçimi ile ilgilidir. İyi bir karma fonksiyonu elemanları t.uzunluk listeleri arasında eşit olarak dağıtır, böylece t[hash(x)] hash listesinin beklenen boyutu O(n/t.uzunluk) = O(1) olur. Bunun yanı sıra, kötü bir fonksiyonu tüm değerleri (x içinde olmak üzere) aynı tablo konumuna karma yapacaktır, bu durumda, t[hash(x)] listesinin boyutu n olacaktır. Bir sonraki bölümde iyi bir karma fonksiyonunu tanımlıyoruz. 114

115 5.1.1 Çarpımsal Karma Yöntemi Çarpımsal karma (Bölüm 2.3 de tartışılan) modüler aritmetiğe ve tamsayı bölünmesine dayalı karma değerlerini üreten etkili bir yöntemdir. Bölümün tamsayı kısmını sonuç olarak hesaplayan ve kalanı hesapsız bırakan div operatörünü kullanır. Her tamsayı a 0 ve b 1 için a div b = a/b doğru olur. Çarpımsal karma yönteminde d, boyutu belirten bir tamsayı olmak üzere, 2d boyutlu bir karma tablo kullanılır. x {0,, 2w 1} olan bir x tamsayısı için verilen karma formülü olur. Burada z {1,, 2w 1} olan rasgele seçilmiş tek tamsayıdır. Bu karma fonksiyonu tamsayılar üzerindeki işlemlerin varsayılan olarak, w bir tamsayının bit sayısı olmak üzere, zaten modülo 2w ile yapıldığını gözlemleyerek, çok etkin bir şekilde gerçekleştirilebilir (bkz. Şekil 5.2.) Ayrıca tamsayının 2w d ile bölünmesi ikili tabanda gösterimde en sağdaki w - d bitten kurtulmayı gerektirir. (w d biti sağa doğru kaydırarak gerçekleştirilebilir.) Böylece, yukarıdaki formülü uygulayan kod formülün kendisinden daha kolay hale gelir: 115

116 Kanıtı bu bölümün sonlarına kadar ertelenen aşağıdaki önerme, çarpımsal karmanın çatışmalardan kaçınmak gibi iyi bir görevi yerine getirdiğini gösteriyor. Önerme 5.1. {0,, 2w 1} içindeki iki ayrı değer x ve y olsun, x y. Önerme 5.1 ile sil (x) ve bul (x) performanslarını analiz etmek kolaydır: Önerme 5.2. Herhangi bir veri değeri x için, nx karma tabloda x elemanının yinelenme sayısı verildiyse, t[hash(x)] listesinin beklenen uzunluğu en çok nx + 2 olur. Kanıt. x e eşit olmayan elemanların (çoklu)-kümesi S ile belirtilsin. y S için gösterge değişkenini tanımlayın. t[hash(x)] Önerme 5.1. ile dikkat edilmelidir ki, listesinin beklenen uzunluğu, gerektiği gibi, olur. Şimdi, Önerme 5.1 i kanıtlamak istiyoruz. Ama ilk olarak sayı kuramının bir sonucuna ihtiyaç duyarız. Aşağıdaki kanıtta, sayısını belirtmek için (br,, b0)2 gösterimini 116

117 kullanıyoruz. burada her bi ikili tabanda 0 veya 1 bitleridir. Bir başka deyişle, (br,, b0)2 ikili tabanda gösterimi br,, b0 ile verilen bir tamsayıdır. Bilinmeyen değeri belirten bit için kullanıyoruz. Önerme 5.3. {1,, 2w 1} kümesindeki tek tamsayıların kümesi S olsun; q ve i S içinde herhangi iki eleman olsun. Bu durumda, z S iken eşitliğini sağlayan sadece bir değer tam olarak vardır. Kanıt. z ve i için eşit sayıda seçim yapılabileceği için eşitliğini sağlayan en fazla bir z S değerinin var olduğunu kanıtlamak yeterlidir. Bir çelişki denemek için, z > z olmak üzere iki ayrı z ve z değeri olduğunu varsayalım. Bu nedenle, Bu eşitlik aynı şekilde k tamsayısı için yeniden yazılır: İkili tabanda gösterilen sayılar açısından düşünüldüğünde, Böylece (z z ) q sayısının ikili gösteriminde sondan w bit 0 olur. Ayrıca k 0 ve z z 0 olduğu için q 0 doğrudur. q tek sayı olduğundan ikili tabanda gösteriminin son biti 0 olamaz: 117

118 z z < 2w olduğu için, z z ikili tabanda gösterimi w bitten daha az sayıda 0 bite sahiptir: Bu nedenle, (z z )q çarpımının ikili tabanda gösterimi w bitten daha az sayıda 0 bite sahiptir: Bu nedenle, (z z )q (5.1) eşitliğini sağlamaz, çelişki olur ve kanıt tamamlanır. Şu gözlemden yararlanırsak, Önerme 5.3 daha iyi anlaşılacaktır: S içinden Z rasgele seçilirse, zt nin S üzerindeki dağılımı normaldir. Aşağıdaki kanıtta size yardımcı olabilecek bir nokta, ikili tabanda z gösterimini w 1 rasgele bitin ardından gelen 1 biti olarak düşünmek olacaktır. Önerme 5.1. Kanıtı: Öncelikle unutmayın ki, hash(x) = hash (y) koşulu zx mod 2w sonucunun en-yüksek dereceden d biti ve zy mod 2w sonucunun en-yüksek dereceden d biti aynıdır. ifadesine eşdeğerdir. Bu açıklamanın gerekli koşulu z(x y) mod 2w sayısının ikili tabanda gösteriminin en yüksek dereceden d biti ya hep 0 ya hep 1 olmalıdır. zx mod 2w > zy mod 2w koşulu ile birlikte veya zx mod 2w < zy mod 2w koşulu ile birlikte 118

119 gösterilir. Bu nedenle, sadece z(x y) mod 2w olasılığını (5.2) veya (5.3) teki bağıntılarla ilişkilendirmek zorundayız. q tek olan tekil tamsayı olsun, öyle ki bazı r tamsayısı için. Önerme 5.3 sayısının ikili tabanda gösterimi w 1 rasgele bit, ardından 1 bit içerir : ile Bu nedenle, sayısının ikili tabanda gösterimi w r 1 rasgele bit, ardından 1 bit içerir : Kanıtı şimdi bitirebiliriz: Eğer r > w d ise, sayısının en yüksek dereceden d sayısının (5.2) veya (5.3) gibi biti hem 0 ve hem 1 leri içerir, böylece görünme olasılığı 0 dır. Eğer r = w d ise (5.2) gibi olma olasılığı 0 dır, ancak (5.3) gibi görünme olasılığı 1/2d-1 = 2/2d olur (çünkü b1,, bd-1 = 1,, 1 doğrudur). Eğer r < w d ise, bw r 1,, bw r d = 0,, 0 veya bw r 1,, bw r d = 1,, 1 doğrudur. Bu durumların her birinin olasılığı 1 / 2d ve ayrışık oldukları için her iki durumun olasılığı 2 / 2d olur Özet Aşağıdaki teorem Zincirleme Karma Tablo veri yapısının performansını özetler: Teorem 5.1. Zincirleme Karma Tablo, Sırasız Küme arayüzünü uygular. yeniden_boyutlandır () için yapılan çağrıların maliyeti dikkate alınmayarak, Zincirleme Karma Tablo işlem başına O(1) beklenen zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. 119

120 Bundan başka, boş bir Zincirleme Karma Tablo oluşturulursa ve ekle(x) ve sil (x) işlemleri m 1 defa çağrılırsa, yeniden_boyutlandır () çağrıları için gerekli toplam çalışma süresi O(m) olur Doğrusal Karma Tablo: Doğrusal Yerleştirme Doğrusal Karma Tablo veri yapısında, i nci listede hash(x) = i olan tüm x elemanlarının depolandığı bir liste dizisi kullanılmaktadır.. Alternatif olarak, açık adresleme ile elemanlar doğrudan, t, dizisi içinde ve her t konumunda en fazla bir değer olacak şekilde depolanabilir. Bu yaklaşım, bu bölümde anlatılan Doğrusal Karma Tablo tarafından uygulanmıştır. Bazı yerlerde, bu veri yapısı doğrusal yerleştirme ile açık adresleme olarak tanımlanmaktadır. Bir Doğrusal Karma Tablo ardındaki ana fikir x elemanını hash(x) = i hash değeri ile ideal olarak t[i] tablo konumunda saklamak istememiz yatıyor. Zaten orada var olan bir eleman saklandığı için bu yapılamıyorsa, o zaman t[(i + 1) mod t.uzunluk] konumunda saklanması istenir. Bu mümkün değilse, t [(i + 2) mod t.uzunluk] konumu denenir, ve böylece, x için bir yer bulunana kadar devam edilir. t içinde saklanan üç tür girdi vardır: 1. veri değerleri: Sırasız Küme de depolanan gerçek değerler. 2. boş (null) değerler: Hiçbir veri kaydı yapılmamış dizi konumlarındaki değerler. 3. del değerler: Verilerin bir zamandan bu yana dizi konumlarında saklandığı ancak silindiği değerler. n eleman sayısının yanı sıra, q ile 1.tür ve 3.tür elemanların sayısı belirtilir. Bunun anlamı, q n ve del değerlerini taşıyan elemanların toplam sayısı olur. Bu işi verimli hale getirmek için, t için ayrılan üst limitin q değişkeninde tutulan değerden nispeten çok büyük olması gerekir. Böylece t içinde ayrılmış pek çok boş değer yeri olmalıdır. Bu nedenle, Doğrusal Karma Tablo üzerinde yapılan işlemler için t.uzunluk q değişmezi tanımlanabilir. 120

121 Özetlemek gerekirse, veri elemanlarını depolamak için Doğrusal Karma Tablo bir t dizisi kullanır, n ve q tamsayıları veri elemanlarının sayısını ve boş-olmayan t değerlerini belirtir. Birçok karma fonksiyonları sadece 2 üssündeki bir sayıya kadar eleman depolayan tablo boyutlarına kadar çalıştıkları için bir d tamsayısı tanımlayabilir ve t.uzunluk = 2d değişmezini koruyabiliriz. Bir Doğrusal Karma Tablo içinde bul (x) işlemi basittir. hash(x) = i olan t[i] dizi pozisyonuyla başlarız. Sırasıyla t[i], t [(i + 1) mod t.uzunluk], t [(i + 2) mod t.uzunluk] pozisyonları aranır, ve böylece, t[i ] = x, ya da t[i ] = null koşullarından en az birini sağlayan bir i konumu bulunana kadar arama devam eder. Bir önceki durum sağlanmışsa, t[i ] elemanı döndürülür. Sonraki durum sağlanmışsa, karma tabloda x elemanının yer almadığı sonucuna varılır ve boş (null) değer döndürülür. ekle(x) işlemini uygulamak da oldukça kolaydır. Tabloda x elemanının henüz depolanmadığını (bul(x) ile) kontrol ettikten sonra, boş (null) veya del değerleri bulunana kadar t[i], t[(i + 1) mod t.uzunluk], t[(i + 2) mod t.uzunluk] pozisyonları aranmaya devam eder. x tam da o pozisyona dahil edilir, q ve n sayıları uygun şekilde güncellenir. 121

122 Şimdiden sonra, sil(x) işlemini uygulamak açık hale geldi. t[i ] = x veya t[i ] = null koşulunu sağlayan bir i endeksi bulunana kadar t[i], t[(i + 1) mod t.uzunluk], t[(i + 2) mod t.uzunluk] pozisyonları aranmaya devam eder. Bir önceki durum sağlanmışsa, t[i0] = del olarak belirlenir ve true döndürülür. Sonraki durum sağlanmışsa, karma tabloda x elemanının yer almadığı sonucuna varılır (ve bu nedenle silinemez) ve false döndürülür. bul (x), ekle (x) ve sil (x) yöntemlerinin doğrulanması del değerlerinin kullanımına bağlı da olsa kolaydır. Bu işlemlerin hiçbiri dolu veya del girişlere boş (null) değer atamaz. Bu nedenle, t[i ] = null olan i endeksine ulaşmak mutlak şekilde x tabloda yer almıyor ve yine aynı anlamda t[i ] bundan önce de her zaman (boş) null değere sahipti ve yine aynı şekilde öncesinde çalıştırılan ekle (i ) işlemleri dizide en fazla i pozisyonuna kadar gittiği, bir başka deyişle i pozisyonundan ileri gitmediği (i +1, i +2 ) anlamına gelir. 122

123 yeniden_boyutlandır () yöntemi boş (null) olmayan girişlerin sayısı t.uzunluk / 2 sayısından fazla hale geldiği zaman ekle (x) tarafından ve t.uzunluk / 8 sayısından az hale geldiği zaman sil (x) tarafından çağrılır. yeniden_boyutlandır () yöntemi diğer dizi-tabanlı veri yapılarında çalıştırılan yeniden_boyutlandır () yöntemi gibi çalışır. Negatif olmayan en küçük d tamsayısı 2d 3 n bulunur, t dizisi 2d boyutuna sahip olacak şekilde yeniden tahsis edilir, ve sonra eski dizide yer alan tüm elemanlar yeni boyutlu t dizisi içine tekrar yerleştirilir. Bunu yaparken, q eşittir n olarak belirlenir, çünkü yeni dizide hiçbir eleman henüz silinmemiştir (del = 0 doğrudur) Doğrusal Yerleştirme Analizi Unutmayın ki ekle (x), sil (x) ve bul (x) işlemleri için t dizisinde yer alan ilk boş (null) giriş bulunduğu zaman (veya bu endeksten öncesinde de olabilir) doğru pozisyon bulunmuş anlamına gelir. Doğrusal yerleştirme analizinde mantık t elemanlarının en az yarısı boştur, bir işlem tamamlaması çok sürmez çünkü hızlı bir şekilde boş (null) girişe ulaşılır. Ancak bu mantık çok kuvvetli değildir, çünkü bize sadece t boyutu hakkında (yanlış) ipucu verir. Burada önemli olan, n, q, ve del arasındaki rastlantısal bağları kuvvetlendirerek onları bu değişkenler cinsinden yeniden boyutlandırma olasılığı ile ilişkilendirmektir. 123

124 Bu bölümün geri kalanı için, hepimiz karma değerlerin birbirinden bağımsız olduğunu ve {0,, t.uzunluk 1 } aralığına normal olarak dağıtılmış olduğunu kabul eder. Bu gerçekçi bir varsayım değildir, ama bize doğrusal yerleştirmeyi analiz etmek için mümkün bir başlangıç noktası sağlar. Bir sonraki aşama, Listeleme Karma adında diğer yöntemi tanıtıyor. Doğrusal yerleştirme için en uygun karma fonksiyonu ayrıştırabilen akıllı bir seçenektir. Bu analiz sırasındaki varsayımımız, t dizisindeki endekslerin tümü için t.uzunluk modüler aritmetiğinin sonucuna göre pozisyon belirlendiği olmuştur (t[i] = t[i mod t.uzunluk]). i pozisyonundan başlayan k uzunluğundaki bir çalıştırma adımından bahsediyorsak tüm dizi girişleri t[i], t[i + 1],, t[i + k 1] null olmadığı takdirde ve aynı zamanda t[i 1] = t[i + k] = null ise, gerçekleşir. Boş (null) olmayan t elemanlarının sayısı tam olarak q ile ölçülür, ekle (x) yöntemi her zaman q t.uzunluk / 2 sağlar. Şu anki bulunduğumuz zamandan öncesinde diziye q eleman, x1,, xq eklenmişti. q değeri yeniden_boyutlandır () işleminin en son çalıştırıldığı anki tabloya işaret eder. Varsayımımız şudur ki tablo elemanlarının her biri karma değer taşımaktadır. Bu değeri hash(xj) ile belirtiyoruz. hash(xj) değerleri normal dağılımlı ve birbirinden bağımsızdır. Bu açıklama ile doğrusal yerleştirmeyi analiz etmek için gerekli önermeyi kanıtlamaya geçebiliriz. Önerme 5.4. i {0,, t.uzunluk 1} olsun. 0 < c < 1 sabiti ile bir işlemin k uzunluğunda i pozisyonundan başlayarak çalışma zaman O(ck) olur. Kanıt. Bir işlem i pozisyonundan başlayarak k uzunluğunda çalışırsa, hash(xj) {i,, i + k 1} olan eleman sayısı k olur. Bu durumun tam olarak olasılığı çünkü her k elemanı için tablo üzerinde doğru pozisyonu bulmak, bu elemanların k konumundan birine karma edilmesini ön şart kılar, ve kalan q k eleman t.uzunluk k tablo pozisyonu için ayrılır Bu tanım k uzunluğunun i pozisyonundan çalışmaya başlamasından büyük bir sayı sonucu üretir, çünkü t[i 1] = t[1 + k] = null. 124

125 Aşağıdaki gösterimde faktoriyel işlemler için Stirling'in Yaklaşımı na (Bölüm 1.3.2) göre hata payı getiren r! (r/e)r yer değiştirmesi yapacağız. Bu sadece çıkarımı kolaylaştırmak için yapılmıştır. Alıştırma 5.4 bütünüyle Stirling in Yaklaşımı kullanılarak titiz bir hesaplama mantığı getiriyor. t.uzunluk 2q t.uzunluk koşulu sağlanarak şekilde pk değerini en yüksek derecede düşündüğünüzde, değerinin en küçük olması gerektiğine karar verirsiniz, bu nedenle (Son adım olarak, her x > 0 için doğruluğu tanım ile sabitlenen (1 + 1/x)x kullanacağız.) e eşitsizliğini olduğundan kanıt tamamlanır. Şimdi açık hale gelmiş olmalıdır ki bul (x), ekle (x) ve sil (x) işlemlerinin beklenen çalışma zamanları Önerme 5.4 kullanarak kolay hale gelmiştir. Doğrusal Karma Tablo nun depolanmayan bazı x değerleri için bul (x) işleminin çalıştırıldığı en kolay bir durumu düşünün. Bu durumda, i = hash(x) değeri {0, t.uzunluk 1} içinde t içeriğinden bağımsız ve rasgeledir. k uzunluğunda bir çalışmanın i kısmı için bul (x) işleminin çalışma zamanı en çok O(1 + k) olur. Böylece, beklenen çalışma zamanı üst sınırı 125

126 Unutmayın ki, k uzunluğu için her çalışmada k artırılır. k2 dersek, yukarıdaki ifade tekrar yazılır: katlanarak azalan dizidir.11 Bu Çıkarımın sonunda varsayımda bulunduk. nedenle, bul (x) işleminin beklenen çalışma zamanı tabloda yer almayan x değeri için O(1) olur. yeniden_boyutlandır() Tablo maliyeti görmezden gelinerek, yukarıdaki analiz Doğrusal Karma işlemlerinin tümü için gerekli sonuçları çıkarmamıza olanak sağlar. Birincisi, bul(x) analizinin ekle(x) işlemine uygulanması ancak x tabloda yer almadığı süre için geçerlidir. x tabloda ise bul(x) işlemini analiz etmek bize x tabloda yer almadığı takdirde ekle(x) için yapılan analiz ile maliyet açısından aynı sonucu üretir. Fonksiyonel düşünüldüğünde sil(x) işlemi de en üst seviyede bul(x) ile sınırlıdır. Özet olarak, yeniden_boyutlandır () için yapılan çağrıların maliyeti dikkate alınmayarak Doğrusal Karma Tablo 11 işlem başına O(1) beklenen zamanda çalışan işlemleri destekler. Dizi Birçok ders kitabında yazılıdır ki koşulunu sağlayacak bir k0 pozitif tamsayısı k k 0 için vardır. 126

127 Yığıt için yapılan yeniden_boyutlandır () analizi amortize zamanda Doğru Karma Tablo için geçerlidir Özet Aşağıdaki teorem Doğrusal Karma Tablo veri yapısının performansını özetler: Teorem 5.1. Doğrusal Karma Tablo, Sırasız Küme arayüzünü uygular. yeniden_boyutlandır () için yapılan çağrıların maliyeti dikkate alınmayarak, Doğrusal Karma Tablo işlem başına O(1) beklenen zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. Bundan başka, boş bir Doğrusal Karma Tablo oluşturulursa ve ekle(x) ve sil (x) işlemleri m 1 defa çağrılırsa, yeniden_boyutlandır () çağrıları için gerekli toplam çalışma süresi O(m) olur Listeleme Karma Yöntemi Doğrusal Karma Tablo yu {x1,, xn} analiz ederken, çok güçlü bir varsayım yapılmıştır: Her elemanlarının hash(x1),, hash(xn) karma değerleri {0,, t.length 1} üzerine bağımsız olarak ve normal dağılmıştır. Bunu yapmanın bir yolu, her girişin tüm diğer kayıtlardan bağımsız olduğu rasgele bir w-bit tam sayı depolayan 2w boyutunda çok büyük bir tab dizisi saklamaktır. Bu şekilde, tab[x.hashcode()] girişinden d-bit tam sayıyı ayıklayarak hash(x) fonksiyonunu gerçekleştirebildik. Ne yazık ki, 2w boyutunda bir dizi depolamak bellek kullanımı açısından engelleyicidir. Bunun yerine, Listeleme Karma yöntemi tarafından kullanılan yaklaşım, w-bit tamsayıyı 127

128 sadece r bite sahip w/r tamsayı tarafından oluşmuş gibi işlemektir. Böylece, Listeleme Karma sadece uzunluğu 2r olan w/r diziye ihtiyaç duyar. Bu dizilerdeki tüm kayıtlar bağımsız w-bit tamsayılarından bağımsızdır. hash(x) karma değerini elde etmek için x.hashcode() değerini w/r adet r-bit tamsayıya böleriz ve bunları bu diziler içine yapılan endeksler gibi kullanırız. Daha sonra hash(x) karma değerini elde etmek için tüm bu değerleri bitsel veya-hariç operatörü ile birleştiririz. Aşağıdaki kod, w = 32 ve r = 4 olduğu zaman bunun nasıl çalıştığını gösterir. Bu durumda, tab, dört sütunlu ve 232/4 = 256 satırlı iki boyutlu bir dizidir. Kolayca doğrulayabilirsiniz ki, her x için hash(x) değeri {0,..., 2d - 1} üzerine normal dağılmıştır. Küçük bir çalışma ile, herhangi iki karma değerinin birbirimden bağımsız olduğunu da doğrulayabilirsiniz. Bunun anlamı Listeleme Karma nın Zincirleme Karma Tablo gerçekleştirimi için Çarpımsal Karma yöntemi yerine kullanılabileceğini ifade eder. Ancak, herhangi bir küme ile verilen n farklı elemanın n bağımsız hash değeri ürettiği doğru değildir. Bununla birlikte, listeleme karma yöntemi kullanıldığında, Teorem 5.2 hala geçerlidir. Buna ait referanslar bu bölümün sonunda verilmiştir Karma Kodları Önceki bölümde tartışılan karma tabloları w bitten oluşan tamsayı anahtarlarını veri ile ilişkilendirmek için kullanıldı. Oysa ki, birçok durumda, tamsayı olmayan anahtarları ile karşılaşırız. Anahtarlarımız dizeler, nesneler, diziler ya da diğer bileşik yapılar olabilir. Bu 128

129 veri türleri için karma tablolarını kullanmak için, bu veri türlerini w-bit karma kodları ile eşleştirmemiz gerekir. Karma kodu eşleştirmeleri aşağıdaki özelliklere sahip olmalıdır: 1. x ve y eşit ise, x.hashcode() ve y.hashcode() eşittir. 2. x ve y eşit değil ise, x.hashcode() = y.hashcode() olasılığı küçük olmalıdır (yaklaşık 1/2w). Birinci özellik eğer karma bir tabloda x elemanını depoluyorsak ve daha sonra x e eşit olan bir y değerine bakıyorsak, o zaman gerektiği gibi x i buluruz koşulunu sağlar. İkinci özellik nesneleri tamsayılara dönüştürmemizden gelen kaybı en aza indirir. Eşit olmayan nesnelerin genellikle farklı karma kodları vardır ve böylece karma tablomuzda farklı yerlerde depolanmış olmaları muhtemeldir koşulunu sağlar Temel Veri Türleri için Karma Kodları char, byte, int ve float gibi küçük temel veri türleri için karma kodlarını bulmak genellikle kolaydır. Bu veri türlerinin her zaman ikili gösterimi vardır ve bu ikili gösterim genellikle w veya daha az bitten oluşur. (Örneğin, Java da byte 8-bitlik bir türdür, ve float 32-bitlik türdür.) Bu durumlarda, biz sadece bu bitleri {0,, 2w 1} aralığında bir tamsayının temsili olarak görüyoruz. İki değer farklı ise, farklı karma kodları olur. Aynı iseler, aynı karma kodu olur. Birkaç temel veri türü w bitten daha fazlasından, ya da bir tamsayı sabiti c için genellikle cw bitten oluşur.(java long ve double türleri c = 2 ile bunun örnekleridir.) Bir sonraki bölümde anlatıldığı gibi, bu veri türleri c bölümden oluşan bileşik nesneler olarak kabul edilebilir Bileşik Nesneler için Karma Kodları Bir bileşik nesne için nesneyi oluşturan parçaların tek tek karma kodlarını birleştirerek bir karma kodu oluşturmak istiyoruz. Bu göründüğü kadar kolay değildir. Bunu becermek için pek çok çözüm yolu bulabileceğinize rağmen (örneğin, bitsel veya hariç işlemleri ile karma 129

130 kodları birleştirerek) bu yollardan çoğu kolayca bozuk hale gelir (bkz Alıştırmalar ) Ancak, 2w bit duyarlılığında aritmetik yapmaya istekli iseniz, o zaman mevcut basit ve sağlam yöntemler vardır. Birkaç parçadan, P0,..., Pr-1, oluşan bir nesne olduğunu varsayalım. Bu parçaların karma kodları, sırasıyla, x0,, xr-1 olsun. O zaman karşılıklı bağımsız rasgele w-bit tamsayılar, z0,, zr-1, ve rasgele 2w-bit tek tamsayı z seçebilir ve nesnemiz için bir karma kodu hesaplayabiliriz: Unutmayın ki, bu hash kodunun 2w-bitlik ara sonucu alarak bunu bir w-bitlik final sonuç haline getirmek için Bölüm de verilen çarpımsal karma formülünü kullanan (z ile çarpan ve 2w ile bölen) bir son adımı vardır. Burada bu yöntemi, 3 parçadan, x0, x1, x2, oluşan basit bir bileşik nesneye uygulamanın bir örneği verilmiştir. Aşağıdaki teorem göstermektedir ki, uygulamasının basit olmasının yanı sıra, bu yöntem kanıtlanabilirlik açısından da iyidir. Teorem 5.3. Her x0,, xr 1 ve y0,, yr 1 tamsayısı {0,, 2w 1} içinde yer alan w bit birer dizi olsun ve i {0,, r 1} olan en az bir i endeksi için varsayın ki, xi yi. O zaman, 130

131 Kanıt. En sondaki çarpımsal karma adımını görmezden geleceğiz ve bu adımın daha sonra nasıl katkıda bulunacağına bakacağız. Tanımlayın: Diyelim ki, h (x0,, xr 1) = h (y0,, yr 1). Bunu şöyle yeniden yazabiliriz: Burada, olur. Genelleştirme kaybı olmaksızın xi > yi kabul edersek, o zaman her bir zi ve (xi yi) en fazla 2w 1 olduğu, ve bu nedenle çarpımları en fazla 22w 2w < 22w 1 olacağı için (5.4) haline gelir. Varsayım olarak, xi yi 0, bu nedenle (5.5) in zi içinde en çok bir çözümü vardır. zi ve t bağımsız olduğundan (z0,, zr 1 karşılıklı bağımsızdır), h (x0,, xr 1) = h (y0,, yr 1) koşulunu sağlayan bir zi seçme olasılığımız en fazla 1/2w olur. Karma fonksiyonunun son adımı çarpımsal karma yöntemini uygulayarak 2w bitlik h (x0,, xr 1) ara sonucunu, son sonuç olan w bitlik h(x0,, xr 1) haline getirmektir. Teorem 5.3 ile, eğer h (x0,, xr 1) h (y0,, yr 1) ise, Pr{h(x0,, xr 1) = h(y0,, yr 1)} 2/2w olur. Özetlemek gerekirse, 131

132 5.3.3 Diziler ve Dizeler için Karma Kodları Daha önceki bölümde elde edilen yöntem değişmez, sabit sayıda bileşenler içeren nesneler için iyi çalışır. Ancak değişken sayıdaki bileşenler içeren nesneler ile birlikte kullanmak istiyorsak, her bileşen için rasgele bir w-bit tamsayı zi gerektirdiğinden bu yöntem bozulur, kullanılamaz. İhtiyacımız kadar zi oluşturmak için bir sözde rasgele dizisi kullanabilirdik ama o zaman zi 'lar birbirinden bağımsız olmazdı ve sözde rasgele sayıların bizim kullandığımız karma fonksiyonu ile kötü etkileşimde olmadığını kanıtlamak zor hale gelirdi. Özellikle, Teorem 5.3 kanıtındaki t ve zi değerleri artık bağımsız değildir. Daha titiz bir yaklaşımla, karma kodları asal katsayılara sahip polinomlara dayandırabiliriz; bunlar bir, p, asal sayısı için modülo p üzerinden değerlendirilen normal polinomlardır. Bu yöntem, asal katsayılı polinomların hemen hemen her zamanki polinomlar gibi davrandığını söyleyen aşağıdaki teoreme dayanır: Teorem 5.4. p bir asal sayı olsun, ve önemsiz-olmayan bir polinomun, f (z) = x0z0 + x1z1 + + xr 1 zr - 1, katsayıları xi {0,, p 1} f (z) mod p = 0 olsun. Bu durumda, denkleminin z {0,, p 1} için en fazla r 1 çözümü bulunur. Teorem 5.4 ü kullanmak için her xi {0,, p 2} olan bir x0,, xr 1 tamsayı dizisini rasgele bir z tamsayısı, z {0,, p 1}, kullanarak aşağıdaki formülle karma ederiz. Formülün sonundaki ek terime, (p-1)zr dikkat edin. Bu terim x0,, xr dizisinin son elemanı xr olarak (p 1) i düşünmemize yardımcı olur. Unutmayın ki, bu eleman dizideki diğer her 132

133 elemandan (her biri {0,, p 2} kümesinde olan) farklıdır. p 1 bir dizi-sonu-belirteci olarak da düşünülebilir. Aynı uzunluktaki iki dizi durumunu ele alan aşağıdaki teorem bu karma fonksiyonunun z seçmek için ihtiyaç duyulan az miktarda rasgelelik için iyi bir getiri sağladığını göstermektedir. Teorem 5.5. p > 2w + 1 asal sayı olsun. Her x0,, xr 1 ve y0,, yr 1 tamsayısı {0,, 2w 1} içinde yer alan w bit birer dizi olsun ve i {0,, r 1} olan en az bir i endeksi için varsayın ki, xi yi. Bu durumda, Kanıt. h(x0,, xr 1) = h(y0,, yr 1) denklemi yeniden şöyle yazılır: x1 y1 olduğundan bu polinom önemsiz-değildir. Bu nedenle, Teorem 5.4 ile, z içinde en fazla r 1 çözümü bulunur. Bu çözümlerden biri olarak z seçilmesinin olasılığı, bu nedenle en fazla, (r 1)/p olur. Unutmayın ki bu karma fonksiyonu, aynı zamanda, iki dizinin farklı uzunluklara sahip olduğu durum ve dizilerin biri diğerine önek olduğu zaman olsa bile ilgilidir. Bunun nedeni, bu fonksiyonun etkin şekilde aşağıda belirtilen sonsuz diziye karma sağlamasıdır. r > r olan r ve r uzunluğunda iki dizi varsa, o zaman bu iki dizi i = r endeksinde farklılık gösterir. Bu durumda, (5.6) Teorem 5.4 ile z içinde en fazla r çözümü bulunan 133

134 haline gelir. Teorem 5.5 ile birleştirildiğinde aşağıdaki daha genel teoremi kanıtlamaya yeterli oluruz. Teorem 5.6. p > 2w+1 asal sayı olsun. Her x0,, xr 1 ve y0,, yr 1 tamsayısı {0,, 2w 1} içinde yer alan w bit birer dizi olsun. Bu durumda, Aşağıdaki örnek kod, bu karma fonksiyonun bir x dizisi içeren bir nesneye nasıl uygulandığını gösterir: Yukarıdaki kod uygulamada kolaylık sağlamak için bazı çarpışma olasılığından fedakarlık etmiştir. Özellikle, d = 31 ile x[i].hashcode() karma kodunu 31-bit değere indirmek için Bölüm deki çarpımsal karma fonksiyonunu uygular. Bu sayede, modülo p = asal sayısı ile yapılan eklemeler ve çarpmalar 63-bit işaretsiz aritmetiği kullanılarak gerçekleştirilebilir. Böylece daha uzun olanın r uzunlukta olduğu iki farklı dizinin aynı karma koduna sahip olma olasılığı, Teorem 5.6 da belirtilen r / (232 5) aksine olur. 134

135 5.4 Tartışma ve Alıştırmalar Karma tabloları ve karma kodları bu bölümde sadece üzerine dokunulan bir araştırmanın büyük ve aktif alanını temsil eder. Karma [10] üzerine yaklaşık 2000 girdi içeren çevrimiçi Bibliyografya ya erişebilirsiniz. Farklı karma tablo uygulama çeşitleri mevcuttur. Bölüm 5.1'de anlatılan yöntem zincirleme ile karma olarak bilinir. Her dizi girişi bir zincir (Liste) içindeki elemanları içerir. Zincirleme ile karma tarihi Ocak 1953 te H.P.Luhn tarafından hazırlanan bir IBM iç bildirisine kadar uzanır. Bu bildiri bağlı listelere de ilk referanslardan biri olarak görünüyor. Zincirleme ile karmaya bir alternatif olarak, tüm verilerin bir dizi içine doğrudan depolandığı, açık adresleme şemaları tarafından kullanılan karmalardır. Bu şemalar, Bölüm 5.2 deki Doğrusal Karma Tablo yapısını içerir. Bu fikir aynı zamanda bağımsız olarak 1950 lerde, IBM deki bir grup tarafından önerilmişti. Açık adresleme şemaları çarpışma çözülümü sorunu ile ilgilenmek zorundadır: iki değerin aynı dizi konumuna karma olması durumuyla. Çarpışma çözümü için farklı stratejiler için vardır; bunlar farklı performans garantisi sağlar, ve burada sık sık anlatılmış olanlardan daha sofistike karma fonksiyonlar gerektirir. Yine karma tablo uygulamalarının başka bir kategorisi mükemmel karma yöntemler diye anılan yöntemlerdir. Bu yöntemler bul(x) işleminin en kötü O(1) zamanda çalıştığı yöntemlerdir. Statik veri kümeleri için her veri parçasını benzersiz bir dizi konumuna eşleştiren mükemmel karma fonksiyonları bulunarak bu gerçekleştirilebilir. Zamanla değişen veriler için, mükemmel karma yöntemleri şunlardır FKS iki-seviyeli karma tablosu [31, 24] ve guguk-kuşu karma yöntemi [57]. Bu bölümde sunulan hızlı arama fonksiyonları muhtemelen herhangi bir veri seti için iyi çalışacağı kanıtlanır olabilen şu anda bilinen en pratik yöntemler arasındadır. Diğer kanıtlanabilir iyi yöntemler Carter ve Wegman ın evrensel karma kavramını tanıtan ve farklı senaryolar için çeşitli karma fonksiyonları anlatan öncü çalışmalarına [14] kadar uzanmaktadır. Bölüm 'de anlatılan listeleme karma, Carter ve Wegman tarafından açıklanmıştır [14], ancak doğrusal karma tabloya (ve diğer birçok karma tablo şemalarına) uygulanmış haliyle analizini Patraşcu ve Thorup a [60] borçluyuz. 135

136 Çarpımsal karma fikri çok eskidir, ve karma folklor parçası gibi görünüyor [48, Bölüm 6.4]. Ancak, z çarpanını rasgele tek sayı olarak seçme fikri ve Bölüm de anlatılan analizi Dietzfelbinger et al. [23] tarafından tartışılmıştır. Çarpımsal karmanın bu sürümü en basitlerinden biridir, ancak ikinin bir faktörü olan çarpışma olasılığı, 2/2d, 2w 2d ile belirtilen bir rasgele fonksiyondan beklediğinizden çok büyüktür. Çarpma-toplama karma yöntemi z ve b rastgele olarak {0,, 22w 1} içinden seçilen fonksiyonunu kullanır. Çarpma-toplama karmasının sadece 1/2d [21] çarpışma olasılığı vardır, ancak 2w-bit duyarlı aritmetik gerektirir. Sabit uzunlukta olan w-bit tamsayı dizilerinden karma kodlar elde etmenin yöntemleri vardır. Özellikle hızlı bir yöntem, çift sayı olan bir r ve {0,, 2w} içinden rasgele seçilen a0,, ar 1 değerleri için [11] ile verilen fonksiyonudur. Bu 1/2w çarpışma olasılığı olan 2w-bit hash kodu verir. Bu çarpımsal karma (veya çarpma-toplama) yöntemi kullanılarak w-bit hash koduna indirilebilir. bu yöntem hızlıdır, çünkü sadece r/2 2w-bit çarpma gerektirir; oysa ki Bölüm de anlatılan yöntem r çarpma gerektiriyordu. (mod işlemleri sırasıyla eklemeler ve çarpım için w ve 2w-bit aritmetik kullanarak, dolaylı olarak meydana gelir.) Bölüm te anlatılan, asal katsayılı polinomların değişken uzunluktaki diziler ve dizelere karma edilerek kullanılması yöntemi, Dietzfelbinger et al. [22] tarafından getirilmiştir. Pahalı bir makine komutuna dayanan mod operatörünü kullanması nedeniyle, ne yazık ki, çok hızlı değildir. Bu yöntemin bazı çeşitleri asal p olarak 2w 1 seçer. Bu durumda mod operatörü ekleme (+) ile ve bitsel-ve (&) işlemi [47, Bölüm 3.6] ile değiştirilebilir. Başka bir seçenek sabit uzunluktaki dizeler için mevcut hızlı yöntemlerden birini c > 1 sabitiyle verilmiş c 136

137 uzunluğundaki bloklara uygulamak ve sonra asal katsayı yöntemini r/c karma kodu sonuç dizisi için uygulamaktır. Alıştırma 5.1. Belirli bir üniversite her öğrencisine herhangi bir kurs için ilk kez kayıt oldukları zaman birer öğrenci numarası atıyor. Yıllar önce 0 ile başlayan bu ardışık tamsayılar şimdi milyonları bulmuştur. Yüz adet birinci sınıf öğrencisi olduğunu ve onların öğrenci sayılarına dayalı karma kodları atamak istediğimizi düşünün. Bu durumda, öğrenci numarasının ilk iki basamağını mı yoksa son iki basamağını kullanmak daha mantıklı olur? Cevabınızı doğrulayın. Alıştırma 5.2. Bölüm 'de verilen karma şemayı düşünün ve varsayalım ki, n=2d ve d w/2. 2. Seçilen herhangi bir z çarpanı için hepsi aynı hash koduna ait n değer mevcut olduğunu gösterin. (İpucu: Bu kolaydır ve herhangi bir sayı teorisi gerektirmez.) 2. z çarpanı verildiğinde, hepsi aynı hash koduna ait n değeri açıklayın. (İpucu: Bu zordur ve birtakım temel sayı teorisi gerektirir.) Alıştırma 5.3. x = 2w d 2 ve y = 3x ise Pr{hash (x)} = Pr{hash (y)} = 2/2d olduğunu göstererek, Önerme 5.1 ile verilen 2/2d sınırının mümkün olan en iyi sınır olduğunu kanıtlayın. (İpucu: İkili tabanda zx ve z3x gösterimlerine bakın ve z3x = zx+2zx gerçeğini kullanın.) Alıştırma 5.4. Bölüm 'de verilen Stirling'in Yaklaşımı nın tüm yorumunu kullanarak Lemma 5.4 tekrar kanıtlayın. Alıştırma 5.5. Bir Doğrusal Karma Tablo ya x elemanını eklemek için ilk null dizi girdisinde x elemanını depolayan aşağıdaki kodun aşağıdaki basitleştirilmiş versiyonunu düşünün. O(n) zamanda çalışan bir dizi ekle(x), sil(x) ve bul(x) işlemlerini örnek vererek bunun n2 zamanda neden çok yavaş çalışabileceğini açıklayın. 137

138 Alıştırma 5.6. String sınıfı için Java hashcode() yönteminin önceki sürümleri uzun dizelerde bulunan tüm karakterleri kullanmayarak çalışıyordu. Örneğin, on altı uzunluğunda karakter dizesi için, karma kodu yalnızca sekiz çift endeksli karakterler kullanılarak hesaplanmıştır. Hepsi aynı karma koduna sahip büyük miktarda dizeleri örnek göstererek bunun neden çok kötü bir fikir olduğunu açıklayın. Alıştırma 5.7. Varsayalım ki, iki w-bit tamsayı olan x ve y bir nesne oluştursun. Neden x y fonksiyonu böyle bir nesne için iyi bir karma kodu sağlamaz, gösterin. Tamamen karma kodu 0 lardan oluşan nesneler içeren büyük bir küme örneği verin. Alıştırma 5.8. Varsayalım ki, iki w-bit tamsayı olan x ve y bir nesne oluştursun. Neden x + y fonksiyonu böyle bir nesne için iyi bir karma kodu sağlamaz, gösterin. Tamamen karma kodu birbirinin aynı olan nesneler içeren büyük bir küme örneği verin. Alıştırma 5.9. Varsayalım ki, iki w-bit tamsayı olan x ve y bir nesne oluştursun. Nesne için karma kodu sadece bir w-bit tamsayı üreten h(x, y) deterministik fonksiyonu ile tanımlansın. Aynı karma koduna sahip olan nesnelerin büyük bir küme oluşturduğunu kanıtlayın. Alıştırma Bazı pozitif tamsayı w için p=2w-1 olsun. Neden bir pozitif tamsayı x için olduğunu açıklayın. (Bu x 2w - 1 olana dek ard arda 138

139 belirlemesiyle x mod (2w 1) hesabını gerçekleştirmek için bir algoritma verir.) Alıştırma Sık kullanılan bazı karma tablo uygulamalarını bulun (Java Collection Framework, HashMap ya da bu kitapta yer alan Karma Tablo veya Doğrusal Karma Tablo uygulamaları gibi) ve bu veri yapısındaki x tamsayıları için bul (x) işleminin doğrusal zaman aldığı tamsayıları depolayan bir program tasarlayın. Yani, aynı tablo konumuna karma edilen cn elemandan oluşan bir n tamsayıdan oluşan bir küme bulun. Uygulamanın ne kadar iyi olduğuna bağlı olarak, sadece uygulama kodunu inceleyerek bunu yapmak mümkün olabilir, ya da belirli değerleri eklemenin ve bulmanın ne kadar zaman aldığını belirlemek için deneme ekleme ve arama işlemlerini gerçekleştiren bazı kodları yazmak zorunda kalabilirsiniz (Bu web sunucularına [17] tehdit niteliği taşıyan denial-ofservice12 saldırılarını başlatmak için kullanılabilir, ve kullanılmıştır.) 12 Hizmet reddi anlamına gelir. 139

140 Bölüm 6 İkili Ağaçlar Bu bölüm bilgisayar bilimlerinin en temel yapılarından birini tanıtıyor: İki Dala Ayrışmış Ağaç13. Burada köken olarak ağaç sözcüğünün kullanılması kağıda çizdiğimizde, sık sık bir ormanda bulunan ağaca benzer şekilleri andırmasından ileri gelmektedir. İkili ağacı tanımlamanın birçok yolu vardır. Matematiksel olarak, ikili ağaç bağlı ve yönsüz hiçbir döngüsü olmayan sonlu grafiktir ve üç dereceden daha büyük dereceye sahip olmayan tepe noktasına sahiptir. Çoğu bilgisayar bilimi uygulamaları için, ikili ağaçlar köklüdür: En çok ikinci derecedeki özel bir r düğümü ağacın kökü olarak adlandırılır. Her u r düğümü için u dan r ye yol üzerindeki ikinci düğüm u nun menşei olarak adlandırılır. u ya bitişik diğer düğümlerin her biri, çocuğudur. İlgileneceğimiz ikili ağaçların çoğu sıralıdır, bu yüzden sol ve sağ çocukları ayrı düşünmenizde fayda vardır. Gösterimlerde, ikili ağaçlar genellikle aşağı doğru kökten yönlenir, çizimin üst kısmında kök vardır. Sol ve sağ çocuklar sırasıyla şekilde (Şekil 6.1) gösterildiği gibi sol ve sağ dallara ayrılır. Örneğin, Şekil 6.2. dokuz düğümlü ikili ağaç gösteriyor. Önemli bir yeri var olan ikili ağaç kavramında birçok yeni terminolojiye duyulmuştur. Geniş kabul gören bazı tanımları listelemek gerekirse, derinlik, ata, çocuk, yükseklik, yaprak, altağaç sayılabilir. İkili ağaç içinde bir u düğümünün derinliği, u düğümü ile kök arasındaki yolun uzunluğudur. Bir u düğümünde durduğunuzu farz edin. w ile belirtilen bir düğüm sizinle başka bir r arasında kalıyorsa w sizin atanız olur, ve siz w ile belirtilen düğümün çocuğu sayılırsınız. Üzerinde durduğunuz düğümden bir altağaç üremişse, siz o altağacın kökü sayılırsınız. Bu altağaç sizin tüm çocuklarınızı içerir. Size ait olan bir düğümün yüksekliği, çocuğunuza giden yolun en uzun mesafesidir. Bir ağacın yüksekliği siz kökte iken hesaplanan yüksekliktir. Hiçbir çocuğunuz yoksa düğümünüz yapraktır. 13 Bu terimi İkili Ağaç olarak tanımlamak çevirmenler tarafından önerilen makul ifadedir. 140

141 Bazı durumlarda, ikili ağacın uç düğümlerini dış düğüm olarak değerlendirmek gereklidir. Sol çocuğu olmayan düğümlerin soluna bir dış düğüm, sağ çocuğu olmayan düğümlerin sağına bir dış düğüm yerleştirmek (Şekil 6.2.b) ikili ağacın kolay doğrulanabilir özelliklerini anlamamıza yardımcı olur. Örnek vermek gerekirse, n 1 koşulunu sağlayan n gerçek düğümlü bir ikili ağacın n+1 dış düğümü vardır. 141

142 6.1 İki Dallı Ağaç: Temel İkili Ağaç u düğümünün ikili ağaç olduğunu ifade etmenin en temel kriteri en çok üç düğümle bağlantılı olduğunu sağlamasıdır. Bu üç düğüm komşu bağlantılar olarak tanımlanır: Ağaçlık koşulunun devamlılığını sağlamak niyetiyle bu üç komşudan biri mevcut değilse, değeri nil olarak atanır. Bununla beraber, ağacın dış düğümleri ve kökün menşei de nil olacaktır. İkili ağacın kendisi köküyle ifade edilmektedir. Kök r ise : Bir düğümün u dan köke yol uzunluğu ile ölçülen derinliği, u, hesaplanabilir bir niceliktir : 142

143 6.1.1 Özyinelemeli Algoritmalar Özyinelemeli algoritmalar kullanılarak ikili ağaç hakkında kolay hesaplanır gerçekler ifade edilir. Örneğin kökü, u, olan bir ikili ağaç için düğüm sayısını (büyüklüğünü) hesaplamak için özyinelemeli olarak u düğümünde köklenmiş iki altağacın boyutları hesaplanır, sonuç bu ikisinin toplamının bir fazlası olarak dönebilir: u düğümünün yüksekliğini hesaplamak için, u nun iki altağacının yüksekliği hesaplanır, en büyüğünün bir fazlası dönebilir: İkili Ağaçta Sıralı-Düğüm Ziyaretleri Bir önceki bölümde elde edilen iki algoritmanın her ikisi de, ikili ağaçtaki tüm düğümleri ziyaret için özyineleme tekniğini kullanır. İkili ağacın düğümlerini ziyaret etme sırasını belirleyen yazılan kodun kendisidir: 143

144 Özyinelemenin ikili ağaca bu şekilde uyarlanması kodu basitleştirir, ancak sorun da yaratması olasıdır. Özyinelemenin maksimum derinliği ikili ağaçta bir düğümün maksimum derinliği, yani ağacın derinliği ile verilir. Ağacın yüksekliği çok fazla olduğu takdirde, özyineleme kendisini fazla tekrar edeceği için Yığıt için ayrılan bellek sömürülerek kullanımı olanak dışı olur ve çöküşe sebep olur. Özyineleme olmadan bir ikili ağaç hesaplaması için nereden geldiğine göre nereye gideceğini kendisi belirleyen bir algoritma kullanabilirsiniz. Bkz. Şekil 6.3. u.parent bir u düğümüne ulaşırsa, daha sonra yapılacak bir sonraki şey sol altağacı, u.left, ziyaret etmek olacaktır. Bu yönden u düğümüne yapılacak bir ziyaret bize sağ altağacın, u.right, yollarını açacaktır. Bu yönden u düğümüne yapılacak bir ziyaret ile u altağacı tamamıyla ziyaret edilmiş olur. Altağaç ziyareti tamamlandıktan sonra menşei düğüm ziyareti ile birlikte süreç sona erer. Aşağıdaki kod, sol, sağ ve menşei düğümlerin nil olmasına izin verecek şekilde bu fikri uyguluyor: Özyinelemeli algoritmalar ile denenen hesaplamalar özyinelemesiz kod için geçerlidir. Örneğin, ağaç boyutunu hesaplamak için, her düğüm ziyaretinde bir sayı değişken artırılarak çözüm bulunabilirdi: 144

145 İkili ağaçların bazı uygulamalarında, menşei düğüm kullanılmaz. Bu durumda, özyinelemeli olmayan bir uygulama hala mümkündür, ancak bulunduğumuz düğümden köke giden yolda Liste (yada Yığıt) veri yapılarından herhangi birinin kullanılması uygun ve gerekli olacaktır. 145

146 Yukarıdaki fonksiyonlara ait gözlemler göstermiştir ki belli özel desen kalıpları ziyarete göre değişmektedir. Bunun anlamı önce ziyaretin deseni belirlenmelidir. Enine aramada düğümler düzey-düzey ziyaret edilmektedir. Kökten başlar, aşağı doğru ilerler, soldan sağa doğru her seviyede düğümler ziyaret edilir (Bkz. Şekil 6.4) Okuyucu katılmayabilir, ancak bazı insanlar, buna okumak diyor. Bu desen Kuyruk veri yapısı ile temsil edilir. Kuyruk ta kök, r, her şeyiyle (veri) hizmete yakın pozisyonda bulunmalıdır. Her adımda, bir sonraki u düğümünü q düğümünden çıkarmalı, sonrasında u işleme konmalı, ve nil değilse sol, sağ düğümler Kuyruk a eklenmelidir. Bu ziyaret istenen deseni size veren bir sırayla düğümleri ziyaret eder. 6.2 Serbest Yükseklikli İkili Arama Ağacı Serbest Yükseklikli İkili Arama Ağacı u.data verisini belirli kriterlere göre taşıyan ve beklendiği üzere u düğümlerini depolayan özelleştirilmiş bir ikili arama ağaç türüdür. Serbest Yükseklikli İkili Arama Ağacı nın özellikleri, örneğin, büyüklük sırası soldan sağa doğru sıralanacaksa, 1) u.left < u.x (yani, sol altağaç elimizdeki değerden küçüktür) yada 2) u.right > u.x (yani, sağ altağaç elimizdeki değerden büyüktür) şartları gözetilir. Bu şartı koşulsuz her düğüm için sağlayan yapı Serbest Yükseklikli İkili Arama Ağacı dır. (Bkz. Şekil 6.5.) 146

147 6.2.1 Arama İkili arama ağacı yapısında bir değere ulaşmak oldukça kolaydır. Kökten başlanır, herhangi bir x düğümü için üç durum söz konusudur: 1. u.left takibi için x < u.x koşulu aranır. 2. u.right takibi için x > u.x koşulu aranır. 3. x = u.x ise aranan düğüme ulaşılmıştır. 3.durum oluştuğunda veya u=nil olduğu takdirde arama birincisinde başarılı, ikincisinde başarısız sonuç döndürür. Serbest Yükseklikli İkili Arama Ağacı nda gerçekleştirilebilecek aramalara iki örnek Şekil 6.6 da gösterilmiştir. İkinci örnekte gösterildiği gibi aramanın başarısız olduğu durumlar hakkında yargıda bulunalım: 1.durum oluştuğunda en son u düğümüne bakarsanız, u.x için büyüklük karşılaştırması yapmaya gerek duymadan x den büyük olan en küçük değer yargısı verebiliriz. Serbest Yükseklikli İkili Arama Ağacı bize bunu garanti eder. 2.durum oluştuğunda, benzer şekilde, x den küçük olan en büyük değer yargısı verilir. Bu matematiksel yargıların yararlı özellikleri Serbest Yükseklikli İkili Arama Ağacı nın içine gömülmüştür. Ancak, arama sonucu onlar belirgin hale gelir. Bu bize arama sonucunu bulmak için tasarlanan bir bul(x) işleminde kullanılabilecek karşılaştırmaların x hedefine sizi götürmede ne kadar kuvvetli bir araç olduğunu size gösteriyor. 147

148 6.2.2 Ekleme Serbest Yükseklikli İkili Arama Ağacı na yeni bir değer eklemek için, ilk olarak x aranır. Onu bulursanız, eklemeye izin verilmez. Aksi takdirde, x için yapılan aramanın en sonunda ulaşılan p düğümünün x ve p.x karşılaştırması yapılır. Büyüklük sıralaması ne gerektiriyorsa sonuca göre elimizdeki p düğümünün sol yada sağ yaprağına x eklemesi doğru bir şekilde gerçekleştirilmiş olur. 148

149 Bir örnek, Şekil 6.7 de gösterilmiştir. Bu sürecin en zaman-alıcı parçası yeni eklenen, u, düğümünün yüksekliğine orantıyla bağlı zamanda çalışan ve ilk yapılan x aramasıdır. En kötü durumda, bu Serbest Yükseklikli İkili Arama Ağacı nın yüksekliğine eşittir. 149

150 6.2.3 Silme Ağacın bir, u, düğümünü (verisiyle birlikte) silme bir İkili Arama Ağacı nda biraz daha zordur. Silinecek u düğümü bir yaprak ise sadece menşei nden onu ayırmak yeterli olacaktır. Bunun için daha iyi bir yöntem vardır: u nun sadece bir çocuğu varsa, ağaçtan u çıkarılarak u ya bağlı düğümler birbirine uç uça eklenir. u menşei, kendi çocuğunu evlat edinmiştir (Bkz. Şekil 6.8): 150

151 Silinecek düğümün ağaçta halihazırda iki çocuğu varsa, ikiden az çocuk için uygun bir arama yapılmalıdır. Uygunluk kriteri şöyle seçilmelidir: Her ne olursa olsun Serbest Yükseklikli İkili Arama Ağacı özellikleri korunmalıdır. Silinecek düğümün değerini seçmek için u düğümünün sağ altağacında u.x değerinin büyük sıralamasına göre bir sonra gelen büyüğü aranır. Her düğüm için sağ çocuk değeri sol çocuktan büyüktür. O zaman sağ çocuğa ait altağacın yapraklarından küçüğünü u nun değeri olarak atayabiliriz. Bu bize gerekli büyüklük sıralamasını sağlar. Böyle bir w düğümü bulunduğunda, u.x değeri w ye aktarılır. Dikkat edilmesi gereken bir konu da u civarında w düğümleri aranmalıdır. w.x değeri u.x değerine yakın olmalıdır. Bunun için u.right altağacında u.x den büyük en küçük değeri bulunur. Bu değeri çocuğu olmadığı için silmek kolaydır (Bkz. Şekil 6.9). 151

152 6.2.4 Özet Serbest Yükseklikli İkili Arama Ağacı nda gerçekleştirilen bul(x), ekle(x) ve sil(x) işlemleri her ağacın kökünden bir yol izlemeyi gerektiriyor. Yol uzunluğu düğümlerin lokasyonuna bağlıdır. Aşağıdaki teorem Serbest Yükseklikli İkili Arama Ağacı veri yapısının performansını özetler: Teorem 6.1. Serbest Yükseklikli İkili Arama Ağacı, Sıralı Küme arayüzünü uygular. İşlem başına O(n) beklenen zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. Serbest Yükseklikli İkili Arama Ağacı yapısı ile ilgili sorun yüksekliğinin girdi verilerin geliş sırasına bağlı olarak önceden belirleyememiş olmamızdır. Yani sadece işlemler değil, ağaç yüksekliği de O(n) olabilir, işlem sayısı çok ise performans olumsuz etkilenir. Verilerin geliş 152

153 sırasına bağlı olarak, eğer bir ikili ağaç zincir oluşmuşsa (yani, son düğüm dışında her düğümün yalnız bir çocuğu varsa), Teorem 6.1 yeterli olmaz. Teorem 4.1 bir çözüm olabilir, çünkü Sıralı Küme Sekme Listesi yapısının gerçekleştirimi Sıralı Küme arabirimi ile O(log n) zamanda çalışır. Serbest Yükseklikli İkili Arama Ağaç larını kullanmak istemiyorsanız O(log n) zamanda çalışan işlemleri gerçekleştiren veri yapıları arasında, Bölüm 7 de işlemlerin beklenen zamanlarının O(log n) sınırında nasıl rasgele elde edildiğini, Bölüm 8 de amortize çalışma zamanlarını O(log n) zamanda tutacak yerel ve tekrarlı oluşturma tekniğini, Bölüm 9 da enkötü-durum çalışma zamanlarının en fazla 4-çocuğa kadar düğümleri kabul eden, yani ikiliolmayan, bir ağaç yapısı ile nasıl gerçekleştirildiğini bulabilirsiniz. 6.3 Tartışma ve Alıştırmalar İkili ağaçlar binlerce yıldır ilişki modellemek için kullanılmıştır. Bunun bir nedeni, ikili ağaçlar soy ağaçlarının doğal modeli olabilir mi sorusuydu. Aile ağacı demek daha doğrusudur. Kök bir insan, sol ve sağ çocuklar ana-baba, ve özyinelemeli olarak devamı sayılabilir. Daha yakın yüzyıllarda, ikili ağaçlar biyolojide tür kavramını modellemekte kullanıldı. Ağacın yaprakları kaybolmamış türleri temsil ederken, iç düğümleri türleşmeyi temsil eder. Örnek olarak, tek bir türün iki ayrı türe dönüşmesine neden olan olayların iki ayrı popülasyonu nasıl oluşturduğu problemi verilebilir. İkili arama ağaçlarının 1950'lerde çeşitli gruplar tarafından bağımsız olarak keşfedildiği düşünülmektedir [48, Bölüm 6.2.2]. İkili arama ağaçlarının koşulları değiştirilerek uygulanan tasarımları sonraki bölümlerde anlatılıyor. Sıfırdan bir ikili ağaç uygularken birkaç tasarım noktasına karar verilmesi gerekir. Bunlardan ilk soru her düğüm menşei ne işaretçi atamış mıdır? Kökten başlayıp yaprağa giden yol izlerseniz, menşei işaretçilerini depolamak zaman ve bellek kaybıdır, gerek yoktur. Ziyaret performansı açısından düşünürseniz, menşei kayıtları savunulur. Özyinelemeli olarak veya dışsal Yığıt yoluyla gerçekleştirmek mümkün olur. Diğer bazı yöntemler için de (eş-dağılımlı yükseklikli ikili arama ağaçlarındaki ekleme veya silme gibi) menşei kayıtları tavsiye edilir. 153

154 Başka bir tasarım sorusu her düğüm için ana-baba yı nasıl temsil etmek gerekir? Bu bölümdeki gerçekleştirim ayrı değişkenler olarak ana-baba yı depoladı. Başka bir seçenek uzunluğu 3 olan bir dizi, p ana-baba yı saklar. u.p[0] sol çocuğu, u.p[1] sağ çocuğu, u.p[2] menşei temsil eder. Bir dizi içinde bu temsil, if gibi, birtakım işlem kontrol cümlelerinin cebir açılımlarına olanak tanır. Ziyaretlerin açıklanması böyle bir sadeleşmeye dayanak sağlar. u.p[i] yönünden gelen bir ziyaretin bir sonraki adımı (u.p[i+1] mod 3) yönünden gelir. Sağ-sol simetrisi olduğunda benzer örnekler ortaya çıkar. u.p[i] için ağaçta kardeş görünüyorsa bu muhakkak ki (u.p[i+1] mod 2) düğümüdür sağaçevir(u) (ikili ağaç olduğu için). Sayfa 163 te belirtilen solaçevir(u), kodları size cebirsel açıklamanın kodu anlamanız için temel sağlayan bir araç olduğunu gösteriyor. Alıştırma 6.1. n 1 düğüme sahip ikili ağacın kenar sayısı n 1 midir? Kanıtlayın. Alıştırma 6.2. n 1 gerçek düğüme sahip ikili ağacın dış sayısı n + 1 midir? Kanıtlayın. Alıştırma 6.3. İkili, T, ağacın en az bir yaprağı varsa, (a) T 'nin kökü en az bir çocukludur. (b) T birden fazla yapraklıdır. Kanıtlayın. Alıştırma 6.4. u düğümünden köklü bir altağacın boyutunu hesaplayan boyut2(u) adında özyinelemeli-olmayan yöntemi uygulayın. Alıştırma 6.5. İkili Arama Ağacı ndaki bir u düğümünün yüksekliğini hesaplayan yükseklik2(u) adında özyinelemeli-olmayan yöntemi uygulayın. Alıştırma 6.6. Eş-dağılımlı ikili ağacın boyutu dengeli olduğu için (Tanım: her u düğümü için sol ve sağ altağaçların düğüm sayısı (eleman) en fazla bir farklılık gösterirse ağaca boyutdengeli denir.) boyutdengeli() adında özyinelemeli bir yöntem uygulayın. Boyut dengeli ise true döndürsün. O(n) çalışma zamanı olsun. Düğümleri farklı lokasyonlarda olan büyük ağaçlarda kodu sınayın. O(n) sağlamayan daha çok zaman alan kod yazmak nispeten kolay olacaktır. 154

155 İkili ağaçta öncül-sıra ziyareti her u düğümünü çocuğundan önce ziyaret eder. içsel-sıra ziyareti her u düğümünü sol altağacını, hemen ardından sağ altağacını, ziyaret ettikten sonra ziyaret eder. arkalı-sıra ziyareti her u düğümünü altağacını ziyaret ettikten sonra ziyaret eder. Ağacın düğüm lokasyonu öncül/içsel/arkalı-sırada ise elemanlarının öncül/içsel/arkalıziyarete göre sıralanması olacaktır. 0,., n 1 için bir örnek Şekil 6.10 da verilmiştir. Alıştırma 6.7. Arama Ağacı nın bir alt sınıfını oluşturun. Bu alt sınıfın veri alanları öncülsıra, arkalı-sıra, ve içsel-sıra içeren sayıları depolamakta kullanılsın. öncülsıradasayılar(), içselsıradasayılar() ve arkalısıradasayılar() adlarında yöntemler geliştirin. Bu yöntemler ağaçta depolanan sayıları belirtilen sırada yazsınlar. Her birinin çalışma zamanı O(n) olmalıdır. Alıştırma 6.8. u dan sonra belirtilen sırada gelmesi gerekli düğümü getiren fonksiyonlar amortize sabit zamanda çalışabilir. Herhangi bir u düğümünden başlatıldığında ve tekrar tekrar bu fonksiyonlardan birini çağırırsanız, u=null olana kadar dönüş değerini u ya atadığınızı düşünün. Bu işlemlerin maliyeti O(n) midir? sonrakiöncülsıra(u), sonrakiiçselsıra(u), ve sonrakiarkalısıra(u) fonksiyonlarını özyinelemeli olmayan şekilde uygulayın. Alıştırma 6.9. Varsayın ki, düğümlerdeki lokasyonları öncül-, arkalı- ve içsel-sırada olan sayıları depolayan ikili ağaç verilsin. Şu soruları cevaplarının -sabit zaman olması için bu rakamları kullanabileceğinizi gösterin: 1. u düğümünden başlayan altağacın boyutunu belirleyin. 1. u düğümünün derinliğini belirleyin. 3. u ve w düğümlerinden biri diğerinin atası mıdır? Belirleyin. (u, w düğümleri aynı değildir.) Alıştırma öncül-sıra ve içsel-sıra taşıyan düğümlerin listesi en çok bir ağaçta toplanabilir. Kanıtlayın ve ağacı oluşturun. Düğüm listesinin verildiğini varsayabilirsiniz. Alıştırma Herhangi bir ikili ağaçtaki düğümlerin lokasyonu en çok 2(n 1) bit kullanılarak temsil edilebilir gösterin. (İpucu: Bir ziyaret sırasında ne olabileceğini düşünün ve ağacı oluşturmak için bu olacakları zihninizde canlandırın.) 155

156 Alıştırma Şekil 6.5 te gösterilen ikili arama ağacına 3,5 ve 4,5 değerlerini eklediğinizde olacakları tanımlayın. Alıştırma Şekil 6.5 te gösterilen ikili arama ağacından 3 ve 4 değerlerini sildiğinizde olacakları tanımlayın. Alıştırma küçüklerintoplamlistesi(x) adında x elemanından küçük düğümlerin değerlerini hesaplayan bir listeyi bize veren İkili Arama Ağacı yöntemini uygulayın. Yönteminiz O(n + h) zamanda çalışmalı x elemanından küçük eleman sayısı n ile belirtilsin ve h ağacın yüksekliğini belirtsin. Alıştırma Başlangıçta boş olan ancak yazdığınız kod sayesinde n 1 yüksekliğine erişen boş İkili Arama Ağacı na elemanları nasıl ekleyebilirsiniz açıklayın. Kaç şekilde bunu yapmanız mümkün olur? Alıştırma İkili Arama Ağacı ve ekle(x), hemen ardından sil(x) gerçekleştirirseniz (x aynı değeri taşıyor olacak) arama ağacındaki düğümlerin lokasyonu mutlaka değişir mi? Farklı kalabilir mi? Aynı olmak zorunda mıdır? Alıştırma İkili Arama Ağacı nda sil(x) işlemi, herhangi bir düğümün yüksekliğini arttırabilir mi? Evetse, kaç yüksekliğinde artırır? Alıştırma İkili Arama Ağacı nda ekle(x) işlemi, herhangi bir düğümün yüksekliğini arttırabilir mi? Ağacın yüksekliğini artırabilir mi? Evetse, kaç yüksekliğinde artırır? Alıştırma İkili Arama Ağacı nın bir versiyonunu tasarlayın ve uygulayın. u düğümünden başlayan altağacın boyutu u.boyut ile belirlensin. Derinliği u.derinlik ile belirlensin. Yüksekliği u.yükseklik ile belirlensin. belirle(x) ve sil(x) işlemleri bu değerleri değiştirebilir, ancak bu maliyetini artırabilir olmamalıdır, sadece sabit oranda artırır veya azaltır şartı aranıyor. 156

157 Bölüm 7 Rasgele İkili Arama Ağaçları Bu bölümde, tüm işlemler için beklenen O(log n) çalışma zamanını rasgelelik kullanarak sağlayan İkili Arama Ağacı tanıtılıyor. 7.1 Rasgele İkili Arama Ağaçları Şekil 7.1 de gösterilen iki ikili arama ağaçları düşünün, bunların her birinin n = 15 düğümü vardır. Soldaki bir listedir, ve öteki mükemmel dengeli ikili arama ağacıdır. Soldaki n 1 = 14 yüksekliğe sahiptir, sağdakinin yüksekliği üçtür. Bu iki ağacın nasıl kurulduğunu düşünelim. Soldaki, boş İkili Arama Ağacı ile başlandığında ve aşağıdaki veri dizisi ağaca sırasıyla eklendiğinde elde edilir. Başka sırada yapılan hiçbir ekleme bu ağacı oluşturmaz (n üzerinde tümevarım yöntemiyle kanıtlanacağı üzere). Diğer taraftan sağdaki ağaç, aşağıdaki dizi tarafından oluşturulabilir: Aşağıdaki diğer diziler de bu ağacı oluşturmak için dahil edilebilir: ve 157

158 İşin gerçeği, sağdaki ağacı oluşturan dizi vardır ve sadece bir dizi soldaki ağacı oluşturur. Yukarıdaki örnek bazı sözel ifade edilen kanıtları bize sağlamaktadır: 0 14 arasında rasgele permütasyon seçilerek ikili arama ağacına eklenirse, o zaman çok dengeli bir ağaç elde etmek (Şekil 7.1 in sol tarafı) çok dengesiz bir ağaç elde etmekten daha olasıdır (Şekil 7.1 in sağ tarafı) denebilir. Bu kavramı rasgele ikili arama ağaçlarını inceleyerek bilimsel bir şekilciliğe şöyle büründürebiliriz: n boyutunda bir Rasgele İkili Arama Ağacı nı şu şekilde elde edebiliriz: 0,, n - 1 arasında rasgele x0,, xn-1 permütasyonu seçin ve elemanlarını teker teker İkili Arama Ağacı na ekleyin. Rasgele permütasyonun anlamı şudur: 0,, n 1 sayılarının olası her bir n! permütasyonu (sıralaması) eşit derecede olasıdır, yani herhangi bir permütasyonu elde etme olasılığı 1/n! olur. Unutmayın ki, 0,, n 1 değerleri, Rasgele İkili Arama Ağacı nın özelliklerinden herhangi birini değiştirmeden, herhangi bir sıralı n eleman dizisi ile yer değiştirebilir.x {0,, n 1} elemanı n boyutunda sıralı bir küme içinde x nci sıradaki elemanı belirtiyor. Rasgele İkili Arama Ağaç ları hakkında verilen ana sonuca gelmeden önce, konudan biraz uzaklaşarak randomize yapılar incelenirken sık sık gündeme gelen bir sayı türünü gündeme getireceğiz. Negatif olmayan bir k tamsayısı için, Hk ile gösterilen k nci harmonik sayı, 158

159 olarak tanımlanır. Harmonik sayı Hk hiçbir basit kapalı formu yoktur, ama çok yakından k nın doğal logaritması ile çok yakından ilgilidir. Özellikle, Matematik okumuş olan okuyucular fark edebilirler ki, olması nedeniyle bu böyledir. İntegral in bir eğri ve x-ekseni arasındaki alan olarak yorumlanabildiğini akılda tutarak, Hk değeri integrali tarafından alt-sınırlanmış ve tarafından üst-sınırlanmış olabilir (Grafiksel açıklama için bkz. Şekil 7.2). Önerme 7.1. n boyutunda Rasgele İkili Arama Ağacı nda herhangi bir x elemanı için arama yolunun beklenen uzunluğu şöyle ifade edilir: 1. Herhangi bir x {0,, n 1} için olur Herhangi bir x ( 1, n) \ {0,, n 1} için 14 olur. x + 1 ve n x ifadeleri sırasıyla ağaçta yer alan x değerinden az veya eşit olan eleman sayısı ve x değerinden büyük veya eşit olan eleman sayısı olarak yorumlanabilir. 159

160 Sonraki bölüm Önerme 7.1 i kanıtlıyor. Şimdilik, Önerme 7.1 in iki bölümünün bize ne düşündürdüğü ile ilgilenelim. Birinci bölüm, n boyutunda bir ağacın içindeki bir eleman için arama yaparsanız, arama yolunun beklenen en fazla uzunluğunun 2ln n + O(1) olduğunu bize anlatıyor. İkinci bölüm bize ağaçta depolanmayan bir değer için yapılan arama hakkında aynı şeyi anlatır. Önermenin bu iki bölümü karşılaştırıldığında ağaçta yer alan bir elemanı aramanın, ağaçta yer almayan bir elemanı aramaktan sadece biraz hızlı olduğu görülüyor Önerme 7.1 in Kanıtı Önerme 7.1 i kanıtlamak için ihtiyaç duyulan en önemli gözlem şudur: Ancak ve ancak T yi oluşturmak için kullanılan rasgele permütasyonda elemanlarından önce gelen bir, i < x düğümü ( 1, n) açık aralığındaki bir x değeri için yapılacak T, Rasgele İkili Arama Ağacı ndaki arama yolu içinde bulunur. Bunu görmek için bkz. Şekil 7.3 te fark etmelisiniz ki eklenene kadar, elemanlarından biri açık aralığındaki her değer için arama yolları özdeştir. (Unutmayın ki, iki değerin farklı arama yolları olması için, ağaçta onlarla farklı karşılaştırılan bazı elemanların bulunması gerekir.) içinde rasgele permütasyonda görünür ilk eleman j olsun. Dikkat edin, x için yapılan her arama yolunda j yol üzerinde bulunmak, yani görünmek zorundadır. Elemanların farklı olduğu durumda, yani j i ise, j elemanını içeren uj düğümü i elemanını içeren ui düğümünden önce oluşturulmuştur kesin olarak doğrudur, çünkü i < j (soldan sağa doğru yer alırlar.) Bu nedenle, şu da kesin olarak doğrudur ki, ağaca i elemanı eklendiğinde, uj.left kökenli altağaca eklenir. Diğer taraftan, x için arama yolu bu altağacı hiçbir zaman ziyaret etmeyecektir, çünkü uj düğümü ziyaret edildikten sonra uj.right altağacına doğru ziyarete devam edilecektir. Benzer şekilde ancak ve ancak T yi oluşturmak için kullanılan rasgele permütasyonda elemanlarından önce gelen i > x düğümü, T, Rasgele İkili Arama Ağacı ndaki arama yolu içinde bulunur. 160

161 {0,, n} rasgele permütasyonu verildiği takdirde, sadece ve dizileri kendi kendilerinin rasgele permütasyonları olur. ve altkümelerinin her elemanı eşit olasılıkla, T yi oluşturmak için kullanılan rasgele permütasyondaki herhangi bir alt kümenin herhangi bir elemanından önce görünecektir. Bu yüzden, Bu gözlem ile, Önerme 7.1 in kanıtı harmonik sayılar ile bazı basit hesaplamalar içermektedir: 161

162 Önerme 7.1 in Kanıtı: Ii göstergesi x için yapılan arama yolunda i bulunduğunda bir, ve aksi takdirde sıfır değerine sahip rasgele değişken olsun. Arama yolunun uzunluğu olarak ifade edilir. Bu nedenle, x {0,, n 1} için arama yolunun beklenen uzunluğu (bkz. Şekil 7.4.a) olur. 162

163 x ( 1, n) \ {0,, n 1} arama değerleri için ilgili hesaplamalar hemen hemen aynıdır (Bkz. Şekil 7.4.b) Özet Aşağıdaki teorem Rasgele İkili Arama Ağacı nın performansını özetler: Teorem 7.1: Rasgele İkili Arama Ağaç, O(n logn) zamanda oluşturulabilir. Rasgele İkili Arama Ağacı nda, bul(x) işlemi, O(log n) beklenen zamanda çalışır. Tekrar vurgulamak gerekir ki, Teorem 7.1 deki beklenti, Rasgele İkili Arama Ağacı nı oluşturmak için kullanılan rasgele permütasyona uygulanmıştır, rasgele x seçimlerine bağlı değil, her x değeri için doğru kabul etmelisiniz. 7.2 Treap: Randomize İkili Arama Ağaçları Rasgele İkili Arama Ağacı ile ilgili sorun dinamik olmamasıdır. Sıralı Küme arayüzünü uygulamak için gerekli ekle(x) veya sil(x) işlemlerini desteklemez. Bu bölümde Treap adında ve Sıralı Küme arayüzünü uygulamak için Önerme 7.1 i kullanan bir veri yapısını tanımlıyoruz15. Treap düğümü, x veri değerine sahip olması ve aynı zamanda p adı verilen ve rasgele atanan özel bir sayısal öncelik içermesiyle, İkili Arama Ağacı düğümüne benzer özellikler taşımaktadır: 15 Treap veri yapısının adı, aynı anda bir ikili arama ağacı olmasından gelen Tree (Bölüm 6.2) ve Heap (Yığın, Bölüm 10) sözcüklerini oluşturan eklerin birleşiminden almıştır. 163

164 İkili Arama Ağacı olmasının yanı sıra, Treap düğümleri Yığın özelliklerini de sağlar: (Yığın Özelliği) Kök hariç, her u düğümünde, u.parent.p < u.p Diğer bir deyişle, her düğüm iki çocuktan daha küçük bir önceliğe sahiptir. Bir örnek, Şekil 7.5 te gösterilmiştir. Her düğüm için key (x) ve priority (p) tanımlanmasının gerçekleşmesiyle birlikte, Yığın ve İkili Arama Ağacı koşulları Treap şeklini tam olarak belirler. Yığın özelliği, minimum öncelikli, r, düğümünün kök olması gerektiğini sağlar. İkili Arama Ağacı özelliği r.x den küçük anahtara sahip tüm düğümlerin r.left kökenli altağaçta saklanmasını, ve r.x den büyük anahtara sahip tüm düğümlerin r.right kökenli altağaçta saklanmasını sağlar. Bir Treap te öncelik değerleri hakkında önemli olan nokta onların tekil ve rasgele atanmalarıdır. Bu nedenle, Treap düşüncesi için iki eşdeğer yol vardır: Yukarıda tanımlandığı gibi Treap, Yığın ve İkili Arama Ağacı özelliklerini sağlar. Alternatif olarak, Treap düğümlerini artan öncelik sırasıyla eklenen bir İkili Arama Ağacı olarak düşünebilirsiniz. Örneğin, Şekil 7.5 te Treap 164

165 (x, p) sıralı ikili değerlerinin İkili Arama Ağacı na eklenmesiyle oluşturulabilir. Öncelikler rasgele seçilmiş olduğundan bu, anahtarların rasgele permütasyonunu almaya eşdeğerdir bu durumda permütasyon elemanlarını İkili Arama Ağacı na eklemek olur. Böylece oluşturulan Treap şekli, Rasgele İkili Arama Ağacı ile aynıdır. Özellikle, her x anahtarını sırası ile yer değiştirirsek16, Önerme 7.1 geçerlidir. Önerme 7.1 Treap bakımından yeniden düzenlenerek şu hale gelir: Önerme 7.2. n anahtardan oluşan bir küme eleman dizisini, S, depolayan bir Treap, için aşağıdaki cümleler geçerlidir: 1. Her x S için, x için arama yolunun beklenen uzunluğu 2. Her x S için, x için arama yolunun beklenen uzunluğu r(x) burada S olur. olur. {x} içinde x sırasını gösterir. Yine, vurgulamalıyız ki Önerme 7.2 de beklenti, her düğüm için rasgele öncelik seçimleri üzerinden belirlenir. Anahtardaki rastgelelik hakkında herhangi bir varsayım gerektirmez. Önerme 7.2 Treaps veri yapısının bul(x) işlemini verimli olarak uygulayabileceğini anlatır. Ancak, Treaps veri yapısının gerçek yararı ekle(x) ve sil(x) işlemlerini desteklemesidir. Bunu yapmak için, Yığın özelliğini korumak için bir döndürüşün gerçekleştirmesine ihtiyaç vardır. Bkz. Şekil 7.6. İkili Arama Ağacı nda bir döndürüş, İkili Arama Ağacı özelliği korunarak, w düğümünün menşei olan u üzerinde yerel bir değişiklik yaparak u menşei olarak w düğümünü belirlemeyi gerektirir. İki çeşit döndürüş vardır: w düğümünün sol veya sağ çocuk olmasına bağlı olarak sırasıyla, sol döndürüş ve sağ döndürüş. 16 x elemanlarından oluşan bir küme eleman dizisi, S, içindeki bir x elemanının sırası x 'den az olan, S elemanlarının sayısıdır. 165

166 Bunu gerçekleştiren kod bu iki olasılığı işlemek zorundadır ve (u kök olduğunda) sınır değerlere dikkat edilmelidir, böylece ortaya çıkan gerçek kodun uzunluğu Şekil 7.6 da gösterildiğinden uzundur. 166

167 Treap u veri yapısı açısından, bir döndürüşün en önemli özelliği w derinliğinin bir azalması ve derinliğinin bir artmasıdır. Döndürüşleri kullanarak, ekle(x) işlemini aşağıdaki gibi uygulayabilirsiniz: Yeni bir u düğümü oluştururuz, u.x = x olarak belirleriz, ve u.p için rasgele değer atarız. Bunu takiben, İkili Arama Ağacı için olağan ekle(x) algoritmasını kullanarak x eklenir. u şimdi Treap veri yapısının yaprağı olmuştur. Bu noktada Treap, İkili Arama Ağacı nın özelliğini yerine getirmektedir, ancak Yığın özelliğini sağlaması hakkında kesin bir şey söylemeyiz. Özellikle, u.parent.p > p u durumu söz konusu olabilir. Bu durumda ise, w=u.parent iken w nin menşei olacak şekilde bir döndürüş gerçekleştirilir. u, Yığın özelliğine aykırı olmaya devam ederse, her tekrarlamada u derinliği bir azaltılarak, u kök olana kadar veya u.parent.p < u.p olana kadar döndürüş tekrarlanır. ekle(x) işleminin bir örneği, Şekil 7.7 de gösterilmiştir. ekle(x) işleminin çalışma süresi x için yapılan arama yolunu takip için gereken süre ve yeni eklenen, u, düğümünün Treap içinde onu doğru olması gerektiği yere kadar taşımak için gerçekleştirilen döndürüş sayısı ile verilir. Önerme 7.2 ile belirtilen arama yolunun beklenen uzunluğu en fazla 2 ln n + O(1) olarak belirlenmiştir. Ayrıca, her bir döndürüşün u derinliğini azalttığı biliniyor. u kök olduğunda döndürüş sona ermelidir, bu nedenle beklenen döndürüş sayısı, gerçekleştirilen arama yolunun beklenen uzunluğundan fazla olmaması gerekir. Bu nedenle, bir Treap tarafından gerçekleştirilen ekle(x) işleminin beklenen çalışma süresi O(log n) olur. (Alıştırma 7.5 bir ekleme sırasında gerçekleştirilen beklenen döndürüş sayısının O(1) olduğunu göstermenizi istiyor.) 167

168 Bir Treap içinde sil(x) işlemi ekle(x) işlemi ile zıt mantığı çalıştırmalıdır. Bunun için, x içeren, u, düğümünü ararız. Bunu takiben u bir yaprak haline gelinceye kadar, u düğümünü aşağı yönde hareket ettirecek döndürüşleri gerçekleştiririz. Treap yapısından u çıkarılarak u ya bağlı düğümler birbirine uç uça eklenir. Dikkat edin, u düğümünü aşağı yönde hareket ettirmek için u düğümünü sırasıyla u.left veya u.right ile yer değiştiren sol veya sağ döndürüşü gerçekleştirebilirsiniz. Aşağıdakilerden hangisi önce geçerliyse, seçim ona göre yapılır: 1. u.left ve u.right her ikisi de null ise, o zaman u bir yapraktır ve hiçbir döndürüş gerçekleştirilmez. 2. u.left (veya u.right) null ise, u düğümünden sağa doğru (veya sırasıyla, sola doğru) döndürüş yapın. 3. u.left.p < u.right.p (veya u.left.p > u.right.p) ise, sağa doğru (veya sırasıyla, sola doğru) döndürüş yapın. 168

169 Bu üç kural Treap bağlantılarının koruyarak, u düğümü silindiğinde Yığın özelliğinin tekrar kazanılmasını sağlar. sil(x) işleminin bir örneği, Şekil 7.8 de gösterilmiştir. sil(x) işleminin çalışma süresini analiz etmekte gerekli olan beceri, bu işlemi ekle(x) işleminin zıttı olarak fark edebilmektir. Özellikle, aynı öncelikte u.p kullanarak x değerini yeniden eklemek isteseydik, ekle(x) işlemi aynı sayıda tam döndürüş yapardı ve Treap özelliklerini sil(x) işleminin gerçekleşmesinden önceki duruma getirerek yeniden korurdu. (Aşağıdan-yukarıya-doğru okumada Şekil 7.8, bir Treap içine 9 değerinin eklenmesini göstermektedir.) n boyutundaki Treap için sil(x) işleminin beklenen çalışma zamanı n 1 boyutundaki Treap için ekle(x) işleminin beklenen çalışma zamanı ile orantılıdır. sil(x) işleminin beklenen çalışma zamanı O(log n) olur. 169

170 170

171 171

172 7.2.1 Özet Aşağıdaki teorem Treap veri yapısının performansını özetler: Teorem 7.1: Treap, Sıralı Küme arayüzünü uygular. Treap işlem başına O(log n) beklenen zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. Treap veri yapısını Sıralı Küme Sekme Listesi ile karşılaştırmak dikkate değerdir. Her ikisi de O(log n) zamanda işlem destekliyor. Her iki veri yapısında da ekle(x) ve sil(x) işlemleri arama gerçekleştirimini takiben sabit sayıda işaretçi değişikliğini içerir (Bkz. Alıştırma 7.5). Bu nedenle, her iki yapı için, performans üzerine etki eden en kritik değer arama yolunun beklenen uzunluğudur. Sıralı Küme Sekme Listesi nde arama yolunun beklenen uzunluğu iken, Treap için bu sayı olur. Bu durumda, Treap kısa arama yolunun getirdiği performansla birlikte Sekme Liste lerine göre yüksek hızlı işlem gerçekleştirme becerisine sahiptir. Bölüm 4 te verilen Alıştırma 4.7 bir Sekme Listesi nin arama yolunun beklenen uzunluğunun nasıl önyargılı para fırlatma aracılığıyla sayısına azaltılabileceğini gösterir. Bu iyileştirme ile olsa bile, Sıralı Küme Sekme Listesi nin beklenen arama uzunluğu yolu Treap ile karşılaştırıldığında uzundur. 172

173 7.3 Tartışma ve Alıştırmalar Rasgele ikili arama ağaçlar hakkında birçok çalışma yapılmıştır. Devroye [19] Önerme 7.1 in kanıtını ve ilgili sonuçlarını vermektedir. Daha kuvvetli sonuçlardan en etkileyici olan başlıcası Rasgele İkili Arama Ağacı nın beklenen yüksekliğini bir formülle ifade eden Reed [64] tarafından literatürde bulunmaktadır. Reed, rasgele bir ikili arama ağacının beklenen yüksekliğinin olduğunu gösteriyor. denklemlerinin [2, ] aralığındaki ve eşsiz çözümü olarak α 4,31107 olarak kaydedilmiştir. Ağacın yüksekliği bir rasgele değişken olduğu takdirde, bu değişkenin ortalama değerinden sapmalarının karelerinin ortalaması olarak tanımlanan değişinti [Kaynak: düşünüldüğünde, yükseklik -rasgele değişkeninin- ortalaması etrafındaki saçılımın sabit olduğu gösterilmiştir. Treap adı Seidel ve Aragon [67] tarafından bilime kazandırılırken, Treap ve bazı varyasyonları tartışıldı. Ancak, temel yapısı Vuillemin [76] tarafından çok daha önceden Kartezyen Ağaçlar olarak literatüre geçmiştir. Treap veri yapısı için olası bir alan-optimizasyonu her düğümdeki öncelikli p alanının açıkça depolanmasının ortadan kaldırılması olabilir. Bunun yerine, bir, u, düğümünün önceliği, u adresini bellekte karma ederek hesaplanır. (32-bit Java da, bu, u. hashcode() kullanılarak karma yapmaya eşdeğerdir). Bir dizi karma fonksiyonu muhtemelen bu uygulama için iyi çalışacaktır, ancak Önerme 7.1 in kanıtının önemli parçalarının geçerli kalması için karma fonksiyonu randomize edilmelidir, ve en küçüklük-bağlamında bağımsızlık özelliği olmalıdır: Ayrı x1,, xk değerleri için h(x1),, h(xk) karma değerlerinin her biri yüksek bir olasılıkla ayrı olmalıdır, ve her i {1,, k} için bazı c sabiti vardır ki, doğru olsun. Bu tür karma fonksiyonlarının uygulaması kolay ve oldukça hızlı olan bir sınıfı listeleme karmadır (Bölüm 5.2.3). Her düğüm noktasında öncelikleri saklamayan başka Treap 173

174 değişimi Martinez ve Roura tarafından Randomize İkili Arama Ağacı [51] olarak bilime kazandırılmıştır. Bu varyasyonda, her u düğümünde kökenli altağacın boyutu u.boyut ile tanımlıdır. ekle(x) ve sil(x) algoritmaları randomizedir. u kökenli alt ağaca x elemanını eklemek için algoritmanın çalışma anlatımı 2 safhada incelenir: 1. 1/(boyut(u)+1) olasılığıyla x değeri her zamanki gibi yaprak olarak eklenir, ve x bu ağacın köküne getirilene kadar döndürüş yapılır. 2. Aksi takdirde, 1 1/(boyut(u)+1) olasılığıyla x değeri özyinelemeli olarak u.left veya u.right kökenli ağaçlardan uygun olan ağaca eklenir. Birinci durumda Treap, x düğümünün u altağacındaki herhangi bir boyut(u) önceliğinden daha küçük olan bir rasgele öncelik aldığı bir ekle(x) işlemine karşılık geliyor, ve bu durum aynı olasılık ile ortaya çıkar. Randomize İkili Arama Ağacı ndan bir x değeri silmek, bir Treap ten silme sürecine benziyor. x içeren u düğümü bulunur, ve art arda u derinliğini artırmak için u bir yaprak haline gelene kadar döndürüş gerçekleştirilir. Bu noktada, u çıkarılarak menşei ve çocukları uç uça birleştirilir. Her adımda sol veya sağ döndürüş gerçekleştirmek seçimi randomize edilmiştir. 1. u.left.boyut/(u.boyut 1) olasılığıyla, u kökenli altağacın kökü u.left olacak şekilde sağ döndürüş gerçekleştirir. 2. u.right.boyut/(u.boyut 1) olasılığıyla, u kökenli altağacın kökü u.right olacak şekilde sol döndürüş gerçekleştirir. Treap siliş algoritmasında bu olasılıklar dahilinde sol veya sağ döndürüş gerçekleşmesi kolayca doğrulanabilir. Treap veri yapısı ile karşılaştırıldığında, Randomize İkili Arama Ağaç larının eleman ekleme ve silme yaparken birçok rasgele seçimler yapması dezavantajdır ve altağaçların boyutları korunmalıdır. Bir elemana erişim zamanı altağaç boyutu cinsinden formüle edilebilir. Treap veri yapısının beklenen erişim zamanının O(log n) olduğu avantaj olarak belirlenmiştir. (bkz.alıştırma 7.10). Treap düğümlerinde depolanan rasgele önceliklerin ise Treap dengesini sağlamak dışında bir getirisi bulunmamaktadır. 174

175 Alıştırma 7.1. Şekil 7.5 te gösterilen Treap içine (7 öncelikli) 4,5 eklemeyi ve daha sonra (20 öncelikli) 7,5 eklemeyi açıklayın. Alıştırma 7.2. Şekil 7.5 te gösterilen Treap içinden 5 ve 7 değerlerinin silinmesini açıklayın. Alıştırma 7.3. Şekil 7.1 in sağ tarafında bulunan ağacı oluşturan dizi olması size yetkin ve yeterli bir değerlendirme gibi mi görünüyor? Kanıtlayın. (İpucu: h yüksekliği cinsinden bir özyinelemeli formül bulun, sonucu ikili ağacı oluşturacak dizilerin sayısı olsun. h = 3 için formülünüzü sınayın.) Alıştırma 7.4. n farklı değerleri sırası rasgele değiştirilmiş şekilde içeren a dizisini girdi olarak alan sırasınıdeğiştir(a) yöntemini tasarlayın ve uygulayın. Yöntemin çalışma zamanı O(n) olmalıdır ve kanıtlamalısınız ki a dizisinin her bir n! olası permütasyonuna eşit olasılıkta rastlanır. Alıştırma 7.5. Önerme 7.2 nin her iki bölümünü de kullanarak ekle(x) ve sil(x) işlemiyle gerçekleştiren döndürüşlerin beklenen sayısı O(1) dir. Alıştırma 7.6. Öncelikleri açıkça depolamayan bir Treap versiyonunu geliştirin. Her düğüm hashcode() ile karma edildikten sonra önceliği işleme koyma becerisine sahip olmalıdır. Alıştırma 7.7. Varsayın ki, İkili Arama Ağaç içindeki her u düğümünde, u kökenli altağacın yüksekliği u.yükseklik ve u kökenli altağacın büyüklüğü, u.boyut depolansın. 1. u düğümünde sol ve sağ döndürüş gerçekleştirildiğinde, bu iki değişkenin döndürüşten etkilenen tüm düğümler için sabit sürede güncellenebildiğini gösterin. 2. Aynı sonucun, her u düğümü için, u derinliğini de depolamaya çalıştığınız takdirde, neden geçerli olmadığını açıklayın. Alıştırma 7.8. En kötü O(n) zamanında çalışan, a adında eleman sayısı n olan sıralı dizinin elemanlarını Treap içine ekleyerek oluşturan bir algoritma tasarlayın ve gerçekleştirin. a elemanları ekle(x) yöntemi ile teker teker eklenseydi, oluşan Treap sizin oluşturduğunuz Treap ile aynı olmalıdır. 175

176 Alıştırma 7.9. Bu alıştırma Treap içinde aradığınız düğüme yakın bir işaretçinin verildiğinde verimli arama yapmanızın ayrıntılarını araştırmada size yardımcı olacaktır. 1. Bir Treap içindeki her düğümün altağacındaki en küçük ve en büyük değerleri depoladığı bir uygulama tasarlayın ve uygulayın. 2. Bu ekstra bilgiyi kullanarak, u düğümüne bir işaretçi yardımıyla bul(x) yöntemini çalıştıran parmakbul (x, u) yöntemini ekleyin. (x içeren düğümden fazla uzak mesafede olmaması tercih edilir.) Bu işlem u düğümünde başlar ve w.min x w.max sağlayacak bir w düğümüne ulaşıncaya kadar yukarıdan ilerler. Bu noktadan itibaren, x için w düğümünden başlayarak standart bir arama yapar. (Gösterilebilir ki, Treap içinde bulunan elemanların sayısı r ile ifade edildiğinde, r değeri x ve u.x arasında olmalıdır, parmakbul(x, u) işleminin çalışma zamanı O(1 + log r) olur. 3. Uygulamanızı tüm bul(x) işlemlerini bul(x) işleminin en son çağrıldığında bulduğu düğümden başlayarak aramayı gerçekleştiren bir Treap versiyonuna doğru genişletin. Alıştırma Treap içinde i nci sıradaki anahtarı döndüren al(i) işlemini içeren Treap versiyonu tasarlayıp uygulayın. (İpucu: Her, u, düğümü u kökenli altağacın boyutunu depolar.) Alıştırma Liste arayüzünün Treap içinde gerçekleştirildiği TreapList adında bir veri yapısını uygulayın. Treap içindeki her düğüm bir Liste arayüzünü gerçekleştirir. Treap için yapılan içsel-sıralamada ziyaret edilen elemanlar aynı sırada, Liste de göründüğü sırada, görünür. Tüm Liste işlemlerinin, al(i), belirle(i, x), ekle(i, x) ve sil(i), beklenen çalışma zamanları O(n) olmalıdır. Alıştırma böl(x) işlemini destekleyen bir Treap versiyonunu tasarlayın ve uygulayın. Bu işlem, Treap içindeki x den daha büyük olan tüm değerleri siler ve tüm silinen değerleri içeren ikinci bir Treap döndürür. Örnek: t2 = t.böl(x) kodu t içinden x den daha büyük tüm değerleri ayırır ve yeni Treap t2 olarak döndürülür. böl(x) işleminin beklenen çalışma zamanı O(log n) olmalıdır. Uyarı: boyut() yönteminin sabit zamanda çalışmasına izin verecek şekilde bu değişikliğin doğru çalışması için Alıştırma 7.10 da belirtilen değişiklikleri uygulamak gereklidir. 176

177 Alıştırma böl(x) işleminin tersi olarak düşünülebilen em(t2) işlemini destekleyen Treap versiyonunu tasarlayın ve uygulayın. Bu işlem Treap, t2, içindeki tüm değerleri siler ve alıcıya ekler. Bu işlemin öngerektirdiği önerme t2 içindeki en küçük değer alıcı içindeki en büyük değerden daha büyüktür olur. em(t2) işlemi beklenen O(log n) zamanda çalışmalıdır. Alıştırma Martinez'in Randomize İkili Arama Ağaç larını gerçekleştirin. Treap ile yapılan bir uygulamanın performansını sizin yapmış olduğunuz uygulamanın performansı ile karşılaştırın. 177

178 Bölüm 8 Günah Keçisi Ağaçları Bu bölümde, Günah Keçisi Ağacı adında İkili Arama Ağacı veri yapısı tanıtılıyor. Bu yapı, ortak akla dayalıdır: Bir şey yanlış giderse, insanların yapmak istedikleri ilk şey birilerini suçlamaktır (günah keçisi). Suçlama sonucu, sorunu çözmek için günah keçisi yalnız bırakılır. Bir Günah Keçisi Ağacı, kısmi-yeniden-oluşturma işlemleri karşısında dengeli davranır. Kısmi-yeniden-oluşturma işlemi sırasında, bütün altağaç parçalara ayrılır ve mükemmel dengeli bir alt ağaç için yeniden oluşturulur. u-düğümü kökenli mükemmel dengeli bir altağacı yeniden oluşturmanın birçok yolu vardır. u altağacını ziyaret etmek, bir diziye bütün düğümleri toplamak, ve sonra özyinelemeli olarak dengeli bir altağacı oluşturmak basit olan yoldur. m = a.uzunluk/2 ise, a[m] yeni ağacın kökü olur, a[0],,a[m 1] özyinelemeli olarak sol altağaçta depolanır, a[m+1],,a[a.uzunluk 1] özyinelemeli olarak sağ altağaçta depolanır. yeniden_oluştur(u) için yapılan bir çağrının çalışma zamanı O(boyut(u)) olur. Elde edilen altağaç minimum yüksekliğe sahiptir; boyut(u) düğümüne sahip olan ağaçlardan daha az yüksekliğe sahip hiçbir ağaç yoktur. 8.1 Günah Keçisi Ağacı: Kısmi Yeniden Oluşturmalı İkili Arama Ağacı Depolanan düğüm sayısı, n, ve düğüm sayısına üst sınır sağlayan bir değişken, q ile belirtildiği takdirde ortaya çıkan İkili Arama Ağacı na Günah Keçisi Ağacı denir. 178

179 Her zaman için, n ve q, aşağıdaki eşitsizliği sağlar: Buna ek olarak, Günah Keçisi Ağacı nın logaritmik özelliğe sahip olan yüksekliği aşağıdaki değeri hiçbir zaman geçmez: 179

180 Hatta bu sayılarla bile, Günah Keçisi Ağacı nın dengesi sınırlanamaz. Şekil 8.1' deki ağaç q = n = 10 bul(x) ile tanımlanır ve yüksekliği için geçerli eşitsizlik 5 < log3/210 5,679 olur. işlemini Günah Keçisi Ağacı nda gerçekleştirmek için İkili Arama Ağacı nın standart arama algoritması kullanılır (bkz. Bölüm 6.2). Yükseklik ile orantılı olduğu için bul(x) işleminin çalışma zamanı (8.1) koşulu nedeniyle O(log n) ile sınırlanır. ekle(x) işlemi için n ve q değişkenlerinin değeri artırılır. İkili Arama Ağacı için gerçekleştirilen algoritma Günah Keçisi Ağacı için de bu artırım yapıldıktan sonra aynen geçerlidir. Önce x aranır, u için u.x = x belirlenimi yapıldıktan sonra, u yeni bir yaprak olarak ağaca eklenir. Bu noktada eğer şanslı olabilirsek, u derinliği log3/2q sayısını aşmayacaktır. Eğer öyleyse, Günah Keçisi Ağacı daha fazla değiştirilmez. Ne yazık ki, bazen derinlik(u) > log3/2q olarak saptanabilir. Bu durumda, çok fazla zahmet gerektirmeyen iş, u düğümünün bulunmasıdır. Derinliği log3/2q sayısını aşan u düğümünden başlayarak köke doğru ilerleriz. Günah keçisi w bulunmalıdır. Günah Keçisi Ağacı nın yüksekliğini yeniden log3/2q yapmak için u düğümü eklendikten sonra, w altağacı yeniden oluşturulur. w kökenli altağaç tamamen yok edilir, yükseklik azaltılır ve mükemmel dengeli İkili Arama Ağacı oluşturulur. 180

181 Günah keçisi, w, çok dengesiz düğümdür. Şu özelliğe sahiptir: w.child kökte u düğümüne giden yolda w düğümünün çocuğudur. u eklenmeden önce (8.2) gösteriyor ki, w altağacı mükemmel dengeli İkili Ağaç değildi, bu nedenle w yeniden oluşturulduğunda, yükseklik en az 1 azalır, böylece Günah Keçisi Ağacı nın yüksekliği yeniden log3/2q olur. Günah Keçisi, w diye adlandırdığımızda, w kökenli altağacı yeniden oluşturmanın maliyetini dikkate almazsak, ekle(x) işleminin çalışma zamanı O(log q) = O(log n) olur. Çalışma zamanına etki eden en büyük faktör yapılan ilk aramadır. Günah Keçisi ni bulmak ve yeniden oluşturmak işleminin maliyeti sonraki bölümde amortize analiz tekniği kullanılarak inceleniyor. Bir Günah Keçisi Ağacı içinde sil(x) uygulaması çok basittir. sil(x) işlemini Günah Keçisi Ağacı na uygulamak için önce x aranır, sonra İkili Arama Ağacı nın standart siliş algoritması kullanılarak x silinir. (Unutmayın ki, ağacın yüksekliği bu işlem sonrasında artmaz.) Sonra, n azaltılır, q aynen bırakılır. En sonunda, q > 2n eşitsizliği kontrol edilir, ve sağlıyorsa tüm ağacın mükemmel dengeli İkili Arama Ağacı haline gelmesi için yeniden oluşturma ile q=n olarak belirlenir. 181

182 Yine, yeniden oluşturma maliyeti dikkate alınmayarak, sil(x) işleminin çalışma zamanı ağacın yüksekliği ile orantılıdır, ve bu nedenle O(log n) olur. 182

183 8.1.1 Doğruluk Analizi ve Çalışma Zamanı Bu bölümde Günah Keçisi Ağacı işlemlerinin doğruluğunu ve amortize çalışma zamanlarını analiz edeceğiz. Doğruluk kanıtlaması için ilk olarak ekle(x) işlemi (8.1) koşuluna itiraz eden bir düğümde sonuçlanırsa, her zaman bir günah keçisi bulunabileceğini göstermemiz gerekiyor: Önerme 8.1. Günah Keçisi Ağacı na eklenmiş u düğümünün derinliği h > log3/2 q ile verilsin. u dan köke giden yol üzerinde bulunan w düğümü için geçerli koşul şudur: Kanıt. Çelişki yaratmak ve sınamak için u dan köke giden yol üzerinde bulunan her w düğümü için bu durumun böyle olmadığını varsayalım. Kökten u düğümüne giden yol r = u0,, uh = u ile ifade edildiği takdirde, size(u0) = n, ve daha genel olarak, Çelişkilidir, çünkü boyut(u) 1 olduğu için buna bağlı olan bağıntılar vardır: Şimdi, çalışma zamanını oluşturan henüz açıklanmamış bileşenleri analiz edeceğiz. İki bölüm içeriyor: Günah keçisi düğümlerini ararken boyut(u) aramalarının maliyeti, ve günah keçisi, 183

184 w, bulunduğunda yeniden_oluştur(w) için yapılan aramaların maliyeti. boyut(u) için yapılan aramaların maliyeti, yeniden_oluştur(w) için yapılan aramaların maliyeti ile aşağıdaki gibi ilişkilendirilebilir: Önerme 8.2. Bir Günah Keçisi Ağacı içinde ekle(x) çağrısı sırasında w günah keçisini bulma ve w kökenli altağacı yeniden oluşturmanın maliyeti O(boyut(w)) olur. Kanıt. w düğümünü bulduktan sonra günah keçisini yeniden oluşturmanın maliyeti O(boyut(w)) olur. Günah keçisi düğümünü ararken u0,..., uk düğümlerinden oluşan dizi için günah keçisi uk = w bulunana kadar boyut(u) çağrılır. Fakat, dizideki günah keçisi olan ilk düğümün uk olması nedeniyle her i {0,, k 2} için bilinmelidir ki, Bu nedenle, boyut(u) için yapılan tüm çağrıların maliyeti olur. Toplamın azalan bir geometrik dizi olması gerçeğinden yola çıkılarak son satırda kanıt tamamlanabildi. 184

185 Önerme 8.3. Boş bir Günah Keçisi Ağacı ile başlandığında, ekle (i, x) ve sil (i) işlemleri toplam m defa çağrılırsa, tüm yeniden_oluştur(u) çağrıları için gerekli toplam çalışma süresi O(m log m) olur. Kanıt. Bunu kanıtlamak için, kredili ağaç geliştirilmiş olup bu, kredilerin yeniden_oluştur(u) için gerekli olanakları sağladığını göstermeye dayanıyor. Her düğümde c kredilik bir sayı depolanırsa, yeniden oluşturma için harcanan zamanda her kredi için, bazı sabit, c ödemeleri gerçekleştirilebilir. Bu temel O(m log m) toplam kredi verir ve yeniden oluşturma için yapılan her çağrı, u tarafından depolanan krediden düşer veya krediye eklenir. Her düğüm 1 kredi içerirse, işlem başına log3/2 q log 3/2 m kredi elde olur. Her düğümün teker teker işleme konduğunu düşünürseniz, toplamda O(m log m) kredi verir. Geriye, bu kredilerin yeniden_oluştur(u) için gerekli krediyi sağladığını göstermek kalıyor. Ekleme sırasında genelleme kaybına girmeden varsayalım ki, Gerçeğini kullanarak bu anlaşılmalıdır ki, ve bu nedenle Şimdi, u içeren bir altağaç son kere yeniden oluşturulduğunda (ya da u eklendiği zaman u içeren bir altağaç, hiçbir zaman yeniden oluşturulmamışsa) 185

186 elde olur. Bu nedenle, u.left ve u.right altağaçlarını etkileyen ekle(x) sayısı ya da sil(x) işlem sayısı Böylece u düğümünde yeniden_oluştur(u) çağrısı için gerekli O(boyut(u)) zamanına yetecek kadar en az bu kadar kredimiz vardır. Silme sırasında yeniden_oluştur(u) çağrıldığında q > 2n doğrudur. q n > n doğrudur. Bu krediye sahibiz ve depolarız. Kökü yeniden oluşturmak için gerekli O(n) zamanı tüketmek için bu kredi yeterlidir. Bu kanıtı tamamlar Özet Teorem 8.1. Aşağıdaki teorem Günah Keçisi Ağacı veri yapısının performansını özetler: Bir Günah Keçisi Ağacı, Sıralı Küme arayüzünü uygular. yeniden_oluştur(u) işlemi için yapılan çağrıların maliyeti dikkate alınmayarak, ekle (x), sil (x) ve bul(x) işlemleri Günah Keçisi Ağacı tarafından işlem başına O(log n) zamanda desteklenir. Ayrıca, boş bir Günah Keçisi Ağacı ile başlandığında, ekle (x) ve sil (x) işlemleri toplam m defa çağrılırsa, tüm yeniden_oluştur (u) çağrıları için gerekli toplam çalışma süresi O(m log m) olur. 186

187 8.2 Tartışma ve Alıştırmalar Günah Keçisi Ağacı, Galperin ve Rivest [33] tarafından tanımlanmış ve analiz edilmiştir. Ancak, aynı yapı, yükseklikleri küçük olduğu sürece herhangi bir şekle sahip olabilen Genel Dengeli Ağaçlar olarak Andersson [5, 7] tarafından daha önce keşfedilmiştir. Günah Keçisi Ağacı Küme uygulaması ile yapılacak denemeler, genellikle bu kitaptaki diğer Sıralı uygulamalarından çok daha yavaş olduğunu ortaya koyacaktır. Bu biraz şaşırtıcı olabilir, çünkü yükseklik sınırı, bir Sekme Listesi ndeki arama yolunun beklenen uzunluğundan daha iyidir ve Treap inkinden de çok uzak değildir. Uygulama alt ağaçların boyutlarını her düğümde açıkça depolayarak ya da zaten hesaplanmış altağaç boyutlarını yeniden kullanarak (Alıştırma 8.5 ve 8.6) optimize edilebilir. Hatta bu iyileştirmelerle bile, her zaman ekle(x) ve sil(x) işlemlerinin Günah Keçisi Ağacı ndaki çalışma zamanları diğer Sıralı Küme uygulamalarından daha uzun sürecektir. Bu performans açığı, aslında, kitapta tartışılan diğer Sıralı Küme uygulamalarının aksine, bir Günah Keçisi Ağacı nın kendisini yeniden yapılandırırken çok zaman geçirebilmesine bağlıdır. Alıştırma 8.3 sizden bir Günah Keçisi Ağacı nın n işlem dizisi için yapılan yeniden_oluştur(u) çağrıları için n log n zaman gerektiğini kanıtlamanızı soruyor. Bu, n işlem sırasında O(n) yapısal değişiklik yapan diğer Sıralı Küme uygulamalarının aksinedir. Bu, ne yazık ki aslında, Bir Günah Keçisi Ağacı nın yeniden yapılandırmak için tüm çağrıları yeniden_oluştur(u) tarafından yapmasının getirdiği gerekli bir sonuçtur. [20]. Performansları iyi olmamasına rağmen, Günah Keçisi Ağacı nın doğru seçim olabileceği uygulamalar vardır. Bu bir döndürüş yapıldığında sabit zamanda güncellenemeyen, ancak bir yeniden_oluştur(u) işlemi sırasında güncellenebilen düğümler ile ilişkili ek veriler olduğu zaman ortaya çıkabilir. Bu gibi durumlarda, Günah Keçisi Ağacı ve kısmi yeniden oluşturmaya dayalı yapılar çalışabilir. Bu tür bir uygulamanın örneği Alıştırma 8.11 de gösterilmiştir. 187

188 Alıştırma 8.1. Şekil 8.1 'de gösterilen Günah Keçisi Ağacı na 1,5 ve 1,6 değerlerinin eklenmesini açıklayın. Alıştırma 8.2. Boş bir Günah Keçisi Ağacı na 1, 5, 2, 4, 3, dizisi eklendiğinde ne olacağını açıklayın. Önerme 8.3 ün kanıtında kredilerin nereye gittiğini ve bu ekleme dizisi sırasında nasıl kullanıldıklarını gösterin. Alıştırma 8.3. Boş bir Günah Keçisi Ağacı ile başlandığında ve x = 1, 2, 3,... n için ekle(x) çağrıldığında, yeniden_oluştur(u) için yapılan tüm çağrıların çalışma zamanının bazı sabit c>0 için en az cn log n olduğunu gösterin. Alıştırma 8.4. Bu bölümde anlatıldığı gibi, Günah Keçisi Ağacı, arama yolunun log3/2q uzunluğunu aşmamasını garanti eder < b < 2 olan bir b parametresi için arama yolunun uzunluğu logbq değerini aşmayan, Günah Keçisi Ağacı nın değiştirilmiş bir sürümünü tasarlayın, analiz edin ve uygulayın. 2. Analiziniz ve/veya deneyleriniz, n ve b cinsinden, bul(x), ekle(x) ve sil(x) amortize maliyetleri hakkında ne diyor? Alıştırma 8.5. Günah Keçisi Ağacı nın ekle(x) yöntemini, zaten hesaplanmış olan alt ağaçların boyutlarını tekrar hesaplamak için zaman harcamayacak şekilde, değiştirin. Bu mümkündür çünkü yöntem boyut(w) değerini hesaplamak istediği zaman zaten boyut(w.left) ya da boyut(w.right) dan birini hesaplamış olması gerekir. Değiştirdiğiniz uygulama ile burada verilen uygulamanın performansını karşılaştırın. Alıştırma 8.6. Her bir düğüm noktasında o düğümde kökenli altağacın boyutlarını depolayan ikinci bir Günah Keçisi Ağacı veri yapısı versiyonunu uygulayın. Bu uygulama ile elde edilen performansı orijinal Günah Keçisi Ağacı uygulamasının yanı sıra Alıştırma 8.5 in uygulaması ile de karşılaştırın. Alıştırma 8.7. Bu bölümün başında tartışılan yeniden_oluştur(u) yöntemini yeniden oluşturulacak altağacın düğümlerini depolamak için bir dizi kullanılmasını gerektirmeyecek şekilde yeniden uygulayın. Bunun yerine, önce bir bağlantılı liste halinde düğümleri bağlamak 188

189 için özyineleme kullanılması ve sonra bu bağlantılı listenin mükemmel bir şekilde dengelenmiş ikili ağaca dönüştürülmesi gerekir. (Her iki adımın da çok iyi özyinelemeli uygulamaları vardır.) Alıştırma 8.8. Ağırlıklı Dengeli Ağaç ı analiz edin ve uygulayın. Kök dışında, her u düğümü boyut(u) (2/3) boyut(u.parent) denge değişmezini korur. Bu ağacın ekle(x) ve sil(x) işlemleri standart İkili Arama Ağacı işlemleri ile aynıdır, bir farkla herhangi bir u düğümünde denge değişmezlik koşulu bozulduğunda u.parent kökenli altağaç yeniden oluşturulur. Analiziniz Ağırlıklı Dengeli Ağaç işlemlerinin amortize çalışma zamanlarının O(log n) olduğunu göstermelidir. 189

190 Bölüm 9 Kırmızı-Siyah Ağaçlar Bu bölümde, Kırmızı-Siyah Ağaç adında, İkili Arama Ağaç larının logaritmik yüksekliği olan bir versiyonu tanıtılıyor. Kırmızı-Siyah Ağaç lar, en yaygın olarak kullanılan veri yapılarından biri olarak bulunmaktadır. Pek çok kütüphane uygulamalarında, Java Koleksiyonlar Çerçevesi ve C++ Standart Şablon Kütüphanesi nin çeşitli uygulamaları da dahil olmak üzere birincil arama yapısı olarak görünür. Aynı zamanda Linux işletim sistemi çekirdeği içinde kullanılır. Kırmızı-Siyah Ağaç ların popülaritesi çeşitli nedenlere dayanır: 1. n değer depolayan bir Kırmızı-Siyah Ağaç en fazla 2 log n yüksekliğe sahiptir. 2. Kırmızı Siyah Ağaç üzerinde ekle(x) ve sil(x) işlemlerinin çalışma zamanı en kötü O(log n) olur. 3. ekle(x) ve sil(x) işlemleri sırasında gerçekleştirilen döndürüşlerin amortize sayısı sabittir. Bu özelliklerin ilk ikisi zaten Kırmızı-Siyah Ağaç larını Sekme Listeleri, Treap ve Günah Keçisi Ağaçları nın önüne koyuyor. Sekme Listeleri ve Treap rasgelelik üzerine dayanır ve O(log n) çalışma zamanı da sadece beklenendir. Günah Keçisi Ağaç ları kendi yüksekliğine garantili bağlıdır, ancak sadece ekle(x) ve sil(x) işlemleri O(log n) amortize zamanda çalışır. Üçüncü özellik sadece kek üzerine krema sürmeye benzer. Bu bize bir x elemanını eklemek veya kaldırmak için gerekli zamanın x i bulmak için gerekli zaman tarafından azımsandığını söylüyor.17 Ancak Kırmızı-Siyah Ağaç ların güzel özellikleri bedava değildir: uygulama karmaşıklığı. Yükseklik üzerindeki 2 log n sınırının sağlanması kolay değildir. Bu durum çeşitli durumların dikkatli analizini gerektirir. Uygulamanın her durumda tam olarak doğru şeyi yaptığından emin olmalısınız. Yanlış bir döndürüş veya renk değişikliği, anlaması ve izlemesi çok zor olabilir bir hata üretir. 17 Unutmayın ki, Sekme Listesi ve Treap de beklenen anlamda bu özelliğe sahiptir. Bkz. Alıştırma 4.6 ve

191 Kırmızı-Siyah Ağaç ların uygulamasına doğrudan atlamadan önce, ilgili bir veri yapısı hakkında biraz bilgi sağlanacaktır: 2-4 Ağaçlar. Bu kırmızı-siyah ağaçların nasıl keşfedildiğine ve neden verimli uygulanabileceklerine dair mümkün olduğunca fikir verecektir Ağacı 2-4 Ağacı aşağıdaki özelliklere sahip (kökü olan) bir ağaçtır: Özellik 9.1 (yükseklik). Bütün yapraklar aynı derinliğe sahiptir. Özellik 9.1 (derece). Her iç düğüm 2, 3 veya 4 çocuk babasıdır. 2-4 Ağaç ın bir örneği Şekil 9.1'de gösterilmiştir. 2-4 Ağaç ın özellikleri, yüksekliğinin yaprak sayısı açısından logaritmik olduğunu göstermektedir: Önerme 9.1. n yapraklı 2-4 ağacı en fazla log n yüksekliğine sahiptir. Kanıt. 2-4 Ağaç ın yüksekliği h ise, bir iç düğümün çocuk sayısı üzerindeki alt sınır olan 2, ağacın en az 2h yaprağa sahip olduğunu anlatır. Bir başka deyişle, Bu eşitsizlikte her iki tarafın da logaritmasını almak h log n verir Yaprak eklenmesi 2-4 Ağaç ına yaprak eklemek kolaydır (Bkz. Şekil 9.2) İkinci-son seviyede bazı düğüm w çocuğu olarak bir yaprak, u, eklemek isterseniz, w çocuğu direkt olarak u olur. Bu kesinlikle yükseklik özelliğini korur, ancak derece özelliğine uymayabilir; u eklenmeden önce w 4 çocuğu varsa; çünkü w şimdi 5 çocuğu olacaktır. Bu durumda, iki düğüm halinde w ikiye 191

192 bölünmelidir, w ve w sırasıyla iki ve üç çocuğu sahip olmalıdır. Ancak şimdi w için bir baba lazımdır, bu yüzden w özyinelemeli olarak w babasının çocuğu yapılır. Yine, bu w babasının çok fazla çocuğa sahip olmasına neden olabilir, bu durumda bölünür. Dört çocuktan daha az olan bir düğüme ulaşana kadar, ya da kök r, iki düğüme, r ve r, bölünene kadar bu süreç devam eder. Sonraki durumda, r ve r çocuklarına sahip yeni bir kök yapılandırılır. Bu her yaprağın derinliğini artırır, ve böylece yükseklik özelliğini korur. 2-4 Ağaç ın yüksekliği en fazla log n olacağı için, yaprak ekleme işlemi en fazla log n aşamadan sonra tamamlanır. 192

193 9.1.2 Yaprak silinmesi 2-4 Ağaç tan bir yaprağı silme biraz daha zordur (Bkz. Şekil 9.3). Baba w ait bir u yaprağı silinir. u silinmeden önce w sadece iki çocuğa sahipse, o zaman w sadece bir çocukla kalır ve 193

194 bu durum derece özelliğine uymaz. Bunu düzeltmek için, w kızkardeşi olan w bakılır. w düğümü mutlaka ağaçta vardır çünkü w babası en az iki çocuğa sahiptir. w üç ya da dört çocuğa sahip olsaydı, çocuklarından biri w verilirdi. Şimdi w iki çocuğu vardır ve w' iki ya da üç çocuğu vardır ve işlem tamamlanır. Öte yandan, eğer w yalnızca iki çocuk sahibiyse, o zaman w ve w üç çocuğu olan tek bir w düğümü haline birleştirilir. Özyinelemeli olarak w babasından w silinir. Bu süreç u ya da kızkardeşinin ikiden fazla çocuğu olduğu durumlarda bir u düğümüne ulaşıldığında, ya da köke ulaşıldığında biter. Sonraki durumda, kök sadece bir çocuk ile bırakılırsa, kök silinir, ve çocuğu yeni kök yapılır. Yine, bu aynı zamanda her yaprağın yüksekliğini azaltır, ve böylece yükseklik özelliğini korur. Yine, ağacın yüksekliği en fazla log n olacağı için, yaprak silme işlemi en fazla log n aşamadan sonra tamamlanır. 9.2 Kırmızı-Siyah Ağacı: 2-4 Ağacı ile Benzeşen Kırmızı-Siyah Ağaç, Ağacı dır. her, u, düğümü kırmızı veya siyah bir renge sahip olan bir İkili Arama Kırmızı rengi 0 ve siyah rengi 1 gösterir. Kırmızı-siyah ağaç herhangi bir işlem öncesi ve sonrasında aşağıdaki iki özelliği sağlar. Her özellik, 0 ve 1 sayısal değerlere atanan kırmızı ve siyah renkler ile ilgilidir. Özellik 9.3 (siyah-yükseklik). Kökten yaprağa giden her yol üzerinde siyah düğüm sayısı aynıdır (yaprağa giden her yol üzerinde renklerin toplamı aynıdır). 194

195 Özellik 9.4 (kırmızı-olmayan-kenar) İki kırmızı düğüm bitişik değildir. Kök dışında, herhangi, u, düğümü için, u.colour + u.parent.colour 1 söylenebilir. Unutmayın ki, bu iki özellikten biri bozulmadan, Kırmızı-Siyah Ağaç ın, r, köküne her zaman siyah rengi vermek mümkün olur, Kırmızı-Siyah Ağaç ı güncelleyen algoritmalar, kökün rengini korur. Kırmızı-Siyah Ağaç lar hakkında bir başka fikir de uç düğümleri (nil) siyah düğüm olarak belirlemektir. Bu şekilde, Kırmızı-Siyah Ağaç ın her gerçek, u, düğümünde iki belirgin çocuğa raslanır. Kırmızı-Siyah Ağaç örneği Şekil 9.4 'de gösterilmiştir Kırmızı-Siyah Ağaçlar ve 2-4 Ağaçlar İlk bakışta Kırmızı-Siyah Ağaç ın siyah-yükseklik ve kırmızı-olmayan-kenar özellikleri gibi sıradışı özeliklerini korumak için verimli bir şekilde güncellenebilir olması size şaşırtıcı görünebilir. Bununla birlikte, kırmızı-siyah ağaçlar 2-4 ikili ağaçların verimli bir simülasyonu olarak tasarlanmıştır. Bkz. Şekil 9.5. n düğümlü herhangi bir kırmızı-siyah ağaç, T, düşünün ve aşağıdaki dönüşümü gerçekleştirin: Her kırmızı u düğümünü kaldırın ve iki çocuğunu direkt siyah menşei ne bağlayın. Bu dönüşüm sonrasında bir T' ağacı sadece siyah düğümlere sahip olacaktır. T' içindeki her iç düğümün, iki, üç, ya da dört çocuğu vardır: İki siyah çocuk ile başlayan siyah bir düğüm bu dönüşümden sonra iki siyah çocuk sahibi olacaktır. Bir kırmızı ve bir 195

196 siyah çocuk ile başlayan siyah bir düğümün, bu dönüşüm sonrasında, üç çocuğu var olacaktır. İki kırmızı çocuk ile başlayan siyah bir düğüm bu dönüşümden sonra dört çocuk sahibi olacaktır. Ayrıca, siyah-yükseklik özelliği T' içinde yapraktan-köke-giden her yolun aynı uzunluğa sahip olduğunu garanti eder. Diğer bir deyişle, T', bir 2-4 ağacıdır! 2-4 ağacının, T', n + 1 yaprağı vardır. Bu nedenle, bu ağaç en fazla log(n+1) yüksekliğe sahiptir. 2-4 ağaçta kökten yaprağa giden her yol, kırmızı-siyah ağaçta, T, kökten bir dış düğüme giden bir yol olarak düşünülüyor. Bu yolda ilk ve son düğümler siyahtır ve her iç düğümden en çok biri kırmızıdır ve bu nedenle bu yol en fazla log(n+1) siyah düğüm ve en fazla log(n+1) - 1 kırmızı düğüm içerir. Bu nedenle, T içinde kökten herhangi bir iç düğüme giden en uzun yol en fazla ile ifade edilir (n 1 için). Bu Kırmızı-Siyah Ağaç ların en önemli özelliğidir: Önerme 9.2. n düğümlü kırmızı-siyah ağacın yüksekliği en fazla 2 log n olur. 196

197 2-4 Ağaç lar ve Kırmızı-Siyah Ağaç lar arasındaki ilişkiyi çözdüğümüz için, bir kırmızı-siyah ağaç oluşturmak ve verimli bir şekilde koruyarak bakımını yapmak için eleman eklenmesi ve silinmesi sırasında güçlük yaşanmayacaktır. İkili Arama Ağacı na eleman eklemek yeni bir yaprak ekleyerek yapılabilir. Bunu önceden görmüştük. Öte yandan, ekle(x) işlemini Kırmızı-Siyah Ağaç a uygulamak için 2-4 Ağaç ın beş çocuklu bir düğümünü ortadan bir yerden ayırmayı gerçekleştirecek bir yönteme ihtiyacımız var. Beş çocuklu bir 2-4 Ağaç ın düğümü iki kırmızı çocuktan birinin yine bir kırmızı çocuğu olan bir siyah düğümü tarafından temsil edilirse, bu düğümü kırmızı ile 197

198 renklendirerek "ortadan bir yerden ayırabiliriz" ve iki çocuğu siyah ile renklendiririz. Bu uygulamanın bir örneği, Şekil 9.6 de gösterilmiştir. Benzer şekilde sil(x) uygulaması için iki düğümü birleştiren ve kızkardeşten bir çocuk borçlanan bir yönteme ihtiyacımız var. İki düğümü birleştirmek, onları ortadan bir yerden bölmek ile zıt kavramlardır (Şekil 9.6 da gösterilmiştir). İki (siyah) kardeşin kırmızı ile renklendirilmesini, ve (kırmızı) menşei nin siyah ile renklendirilmesini içerir. Bir kardeşten borçlanma için döndürüşler ve yeniden renklendirmeler gerekir, en karmaşık yönergelerden biridir. Tabii ki, tüm bunlar boyunca siyah-yükseklik ve kırmızı-olmayan-kenar özelliğini korumamız gerekiyor. Bunun yapılabilir olması şaşırtıcı değildir, dikkate alınması çok sayıda durumlar vardır. Özellikle Kırmızı-Siyah Ağaç ı bir 2-4 Ağaç ile doğrudan benzeştirmek isterseniz, yeri gelir ki, sadece 2-4 Ağaç ı göz ardı etmeniz ve Kırmızı Siyah Ağaç ın özelliklerini sağlamaya çalışmanız daha kolay olur Kırmızı-Siyah Ağaçlarda Sola-dayanım Kırmızı-Siyah Ağaç ları anlamak için sadece bir tanıma başvurmak yetersiz kalacaktır. En gerekli şart, ekle(x) ve sil(x) işlemleri sırasında siyah-yükseklik ve kırmızı-olmayan-kenar özelliklerinin korunması ve yönetilmesidir. Kırmızı-Siyah Ağaç veri yapısı bu koşulun yanı sıra bir başka koşulu da yerine getirir: Özellik 9.5 (sola-dayanım). Herhangi bir, u, düğümünde, u.left siyah ise u.right siyahtır. Şekil 9.4 de gösterilen Kırmızı-Siyah Ağaç sola-dayanım özelliğini sağlamıyor, nedeni ise en sağdaki yol üzerindeki kırmızı düğüm menşeinin kırmızı ve siyah iki çocuğu olmasıdır. Sola-dayanım özelliğini korumaktaki neden ekle(x) ve sil(x) işlemleri sırasında karşılaşılan durumların sayısını azaltmaktır. 2-4 Ağacı açısından, her 2-4 Ağacı nın eşsiz bir şekilde temsil edildiğini anlatır: İki derecesindeki bir düğüm iki siyah çocuklu bir siyah düğüm haline gelir. Üç derecesindeki bir düğüm sol çocuğu kırmızı ve sağ çocuğu siyah olan siyah bir 198

199 düğüm haline gelir. Dört derecesindeki bir düğüm iki kırmızı çocuklu siyah bir düğüm haline gelir. ekle(x) ve sil(x) gerçekleştirimini ayrıntılı olarak irdelemeye başlamadan önce bu yöntemler tarafından kullanılan ve Şekil 9.7 de gösterilen bazı kolay altprogramları sunuyoruz. İlk iki altprogram siyah-yükseklik özelliğini korurken renkleri değiştirmek için kullanılır. pushblack(u) yöntemi iki kırmızı çocuğu olan siyah bir u düğümünü girdi olarak alır, aynı ağaç üzerinde iki siyah çocuğu olan kırmızı bir düğüm haline getirir. pullblack(u) yöntemi, bu işlemin zıttını kırmızı ve siyahı yer değiştirerek gerçekleştirir. solaçevir(u) yöntemi u ve u.right düğümlerinin renklerini değiştirir ve sonra u düğümünde sola döndürüş gerçekleştirir. Bu yöntem, bu iki düğümün renklerinin yanı sıra menşei-çocuk ilişkisini tersine çevirir: 199

200 solaçevir(u) işleminin yararı (u.left siyah ve u.right kırmızı olduğu için) sola-dayanım özelliğini bozan u düğümündeki sola-dayanımı tekrar geri kazandırmasındandır. Bu özel durumda, bu işlemin siyah-yükseklik ve kırmızı-olmayan-kenar özelliklerini de koruyacağından emin olabilirsiniz. solaçevir(u) işlemi için sağaçevir(u) işlemindeki tüm sağlar sol ve sollar sağ olduğu için simetriktir Ekleme Yeni bir yaprak, u, eklemek için Kırmızı-Siyah Ağaç ın ekle(x) uygulamasında standart İkiliArama Ağacı eklemesi yaparız. u.x = x, ve u.colour = red olarak belirlenir. Unutmayın ki, ekleme herhangi bir düğümün siyah yüksekliğini değiştirmez, bu nedenle siyah-yükseklik özelliği hiçbir zaman bozulmaz. Ancak, bu işlem sola-dayanım özelliğini bozabilir (u menşei nin sağ çocuğu olması durumunda). Bu işlem kırmızı-olmayan kenar özelliğini de bozabilir (u menşei nin kırmızı olması durumunda). Bu özellikleri geri yüklemek için, ekletamiri(u) yöntemini çalıştırıyoruz. 200

201 Şekil 9.8 de gösterilen, ekletamiri(u) yöntemi girdi olarak kırmızı-olmayan-kenar özelliği ve/veya sola-dayanım özelliğini bozan ve rengi kırmızı olan bir u düğümü alır. Bu yöntem ile ilgili, Şekil 9.8 e başvurmadan ya da bir parça kağıt üzerinde yeniden yapmadan anlaşılması zor gözlemler aşağıda verilmiştir. (İpucu: u kendiniz, g davranışınız yerine koyabilirsiniz. g u nun u büyükannesi olarak anılmaktadır. w ise sizin babanızdır.) ağacın kökü ise, o zaman her iki özelliği de sağlaması için rengi siyah olarak belirlenebilir. Aynı zamanda u nun kızkardeşi kırmızı ise, o zaman u menşei kesinlikle siyahtır, bu nedenle sola-dayanım ve kırmızı-olmayan-kenar özelliklerinin her ikisi tutarlı olarak sağlanır. Aksi takdirde, işler biraz karışır. İlk olarak u menşei, w, sola-dayanım özelliğini bozduğu belirlenir, ve eğer öyleyse, solaçevir(u) işlemi çalıştırılır ve u = w olarak belirlenir. Bu bizi iyi tanımlanmış bir duruma götürür: u, menşei w nin sol çocuğu olur, bu nedenle şimdi w sola-dayanım özelliğini sağlar. Geriye, kırmızı-olmayan kenar özelliğini sağlama almak 201

202 kalıyor. Sadece w nin kırmızı olduğu durum hakkında endişelenmemize gerek vardır, çünkü aksi takdirde u kırmızı-olmayan-kenar özelliği zaten sağlamaktadır. Henüz işimiz bitmedi. u kırmızı, w kırmızı iken, düşünün ki, u nun büyükannesi g vardır. Bu durumda sadece u tarafından bozulan, fakat w tarafından sağlanan kırmızı-olmayan-kenar özelliği g düğümünün siyah olduğundan bizi emin kılar. g nin sağ çocuğu kırmızı ise, o zaman sola-dayanım özelliği g nin çocuklarının kırmızı olduğunu garanti eder ve pushblack(g) çağrısı g rengini kırmızı ve w rengini siyah yapar. Böylece kırmızı-olmayan- kenar özelliği u düğümü için yeniden sağlanır, ancak özellik g tarafından bozulabileceği için sürecin tamamı u = g için yeniden çalıştırılır. g nin sağ çocuğu siyah ise, sağaçevir(g) için yapılan bir çağrı w düğümünü g düğümünün (siyah) menşei yapar, w için iki kırmızı çocuk ortaya çıkar: u ve g. Böylece u kırmızıolmayan-kenar özelliğini sağlar, ve g sola-dayanım özelliğini sağlar. Ağaç yeniden KırmızıSiyah Ağaç tır. 202

203 ekletamiri(u) yönteminin bir döngüsünün çalışma zamanı sabittir ve her bir yineleme ya işlemi bitirir ya da u lokasyonunu köke yakınlaştırır. Bu nedenle, ekletamiri(u) yönteminin döngü sayısı O(log n) çalışma zamanı O(log n) olur Silme Tüm Kırmızı-Siyah Ağaç varyasyonlarının hepsinde sil(x) işlemi için çok karmaşık olduğu sonucuna varılmıştır. İkili Arama Ağacı nda olduğu gibi sil(x) işlemi bir tane u çocuklu w düğümünü bulur ve w yi silerek, w.parent = u belirlemesiyle çocuk silinen menşei nin menşei ile uç uça birleştirilir (İpucu: u kendiniz, w ise sizin babanız yerine koyarsanız, babamı doğuran büyükannem beni evlatlık edinmiş oluyor). Burada w siyah ise, siyah-yükseklik koşulu şimdi de menşei olan w.parent tarafından bozulmuştur. Renk ayarlaması yapılarak, w.colour = u.colour belirlenir. Bu önleme geçicidir, yeterli olmayabilir: 1) Sürecin başlangıcında eğer u ve w açıkça siyahsa u.colour + w.colour = 2 (iki-kat-siyah). Fakat böyle bir renk sözkonusu olamaz (sadece 0 kırmızı ve 1 siyahtır). Öte yandan, w kırmızı olsaydı, siyah u düğümü tarafından rengi değiştirilecekti. Çözüm olamaz, 203

204 çünkü sola-dayanma özelliği u.parent düğümünde patlak veriyor. Ağacın geçmiş özellikleri, silmeyi de düğümlere uygun hale getirmeyi gerekli kılıyor. siltamiri(u) yöntemi bu amaçla çağrılmaktadır. siltamiri(u) yöntemi girdi olarak rengi siyah (1) iki kat siyah (2) olan bir u düğümü alır. u iki-kat-siyah ise, siltamiri(u) bir dizi döndürüş gerçekleştirir ve yeniden renklendirir. İki-katsiyah düğüm yok edilene kadar ağaç seviyelerinde yukarı çıkarılır. Bu işlem sırasında, u düğümü süreç sonunda ağacın köküne gelinceye kadar değişir. Kökte renk değiştirilebilir. Özellikle, kırmızıdan siyaha geçiş olabilir, böylece siltamiri(u) yöntemi u menşei nin soladayanma özelliğini bozduğunu kontrol ederek bitirir, ve öyleyse düzelterek özelliği geri kazandırır. siltamiri(u) yöntemi tarafından ele alınması gereken durumlar okuyucuya takip kolaylığı sağlaması bakımından Şekil 9.9 da gösterilmiştir. Unutmayın ki, siltamiri (u) yöntemi ikikat-siyah düğümleri işlemektedir. Başvuru yapıldığı takdirde 4 durum tespit edilir: Durum 0: İşlemesi en kolay olan u kök durumudur. u siyah olarak yeniden renklendirilir (Bu kırmızı-siyah ağaç özelliklerinin hiçbirini bozmaz). Durum 1: u nun kızkardeşi olan v kırmızı renkte başlanır. u, menşei olan w ye göre, sol çocuktur (sola-dayanma özelliği nedeniyle). w sağa çevrilir ve döngüye devam edilir. 204

205 Unutmayın ki, w.parent (yeni büyükanne) sola-dayanma özelliğini bozar, sonuç itibariyle u derinliği artmıştır. Unutmayın ki, w kırmızı iken Durum 3 de işletilebilir. Eğer öyleyse, döngü en fazla bir kere sonrasında sona erer. Durum 2: u nun kızkardeşi olan v siyah renkte başlanır. u, menşei olan w ye göre, sol çocuktur. pullblack(w) için yapılan bir çağrı sonrasında u siyah, v kırmızı, w siyah yada ikikat-siyah renk alır. w sola-dayanma özelliğini bozacağı için, solaçevir(w) için yapılan bir çağrıyla düzeltilir. Bu andan itibaren, w kırmızı, v başladığımız altağacın köküdür. w nin kırmızı-olmayan-kenar özelliğini bozduğu kontrol edilmelidir. w nin sağ çocuğu olan q devreye sokarak bunu başarabiliriz. Eğer q siyah olarak belirlenmişse, w kırmızı-olmayan-kenar özelliğini sağlıyor denir. u = v belirlemesi sonrasında döngüye devam edilir. Aksi takdirde, q kırmızı iken, q kırmızı-olmayan-kenar özelliğini, w sola-dayanma özelliğini bozar. Sola-dayanma özelliği solaçevir(w) için yapılan bir çağrı tarafından düzeltilir. v nin sol çocuğu olan q, q nin sol çocuğu olan w, q ve w kırmızı iken v siyah yada iki-kat-siyah olur. sağaçevir(q) çağrısı q düğümünü hem v hem w düğümlerinin menşei yapar. pushblack(q) çağrısıyla v siyah w siyah olarak belirlenir, bu sayede, q rengi v altağacı kökünün, ilk belirtilen w, rengini alır. Bu andan itibaren, iki-kat-siyah düğüm ortadan kaldırılmış ve aynı zamanda kırmızı-olmayankenar ve siyah-yükseklik özellikleri geri kazanılmış olur. Yalnız v sağ çocuğu kırmızıysa, sola-dayanma özelliği bozulmuştur. Gerekiyorsa, solaçevir(v) için yapılan bir çağrı bu özelliği geri kazandıracaktır. 205

206 Durum 3: u nun kızkardeşi siyah renkte başlanır. u, menşei olan w ye göre, sağ çocuktur. Bu durum 2.Durum ile simetrik olduğu için benzer şekilde kodlanmalıdır. Tek fark soladayanım özelliğinin asimetrik olması ve farklı bakım arzetmesidir. Daha önce de, pullblack(w) için yapılan bir çağrı sonucunda v kırmızı u siyah renk almıştı. sağaçevir(w) için yapılan bir çağrı sonucunda, v altağacın kökü haline gelir. Bu andan itibaren w kırmızıdır, w nin sol çocuğu olan q rengine göre kod iki dala ayrışır. 206

207 q kırmızı ise, kod 2.Durum da olduğunun aynısı gibi işler, ve sola-dayanma özelliğini hiçbir düğümün bozma tehlikesi yoktur. 207

208 q siyah ise, durum daha karmaşıktır. v'nin sol çocuğunun rengi kırmızı ise, iki kırmızı çocuk sahibidir. ve iki-kat-siyah v düğümü pushblack(v) çağrısı ile u menşei olan w nin orijinal rengine bürünür, işlem tamamlanır. v nin sol çocuğunun rengi siyah ise, v sola-dayanım özelliğini bozar. solaçevir(v) çağrısı için yapılan bir çağrı ile bu özellik geri kazandırılır. v altağacında siltamiri(u) döngüsünü çalıştırmak için u = v olarak belirlenir. siltamiri(u) süreçleri için döngü çalışma zamanı sabittir. Durum 2 ve 3 bağlamında u nun ağaçtaki yeri köke yakın yada sonlu hale gelebilir. Durum 0 (u kök olduğu için) her zaman sonlanır. Durum 1 hemen Durum 3 ile benzeşir ve sonludur. Ağacın yüksekliği en az 2 log n olduğu için siltamiri (u) döngü sayısının en çok O(log n) sonucuna varılabilir, bu nedenle siltamiri(u) süreçlerinin her birinin çalışma zamanı O(log n) olur. 9.3 Özet Aşağıdaki teorem Kırmızı-Siyah Ağaç veri yapısının performansını özetler: Teorem 9.1. Kırmızı-Siyah Ağaç, Sıralı Küme arayüzünü uygular. Kırmızı-Siyah Ağaç işlem başına O(log n) en-kötü zamanda çalışan ekle(x), sil(x) ve bul(x) işlemlerini destekler. Aşağıda ekstra bir teorem daha veriliyor: Teorem 9.2. Boş bir Kırmızı-Siyah Ağaç ile başlandığında, ekle(x) ve sil(x) işlemleri toplam m defa çağrılırsa, tüm ekletamiri(u) ve siltamiri(u) çağrıları için gerekli toplam çalışma süresi O(m) olur. Sadece Teorem 9.2 ın kanıtını kabaca açıklayacağız. ekletamiri(u) ve siltamiri(u) algoritmalarını 2-4 Ağacı na bir yaprak ekleme veya silme algoritmaları ile karşılaştırdığımızda, bu özelliğin 2-4 Ağacı ndan devralındığına kendimizi ikna edebiliriz. Özellikle, 2-4 Ağacı nı ayırma, birleştirme ve ödünç alma için gerekli toplam zamanın O(m) olduğunu gösterebilirsek, o zaman Teorem 9.2 de gösterilmiş olur. 208

209 Bu teoremin 2-4 Ağaç lar için kanıtlanmasında amortize analizin potansiyel yöntemi kullanılmıştır Ağacı ndaki bir, u, iç düğümün potansiyelini şöyle tanımlayalım: ve 2-4 Ağaç ın potansiyeli düğümlerin potansiyellerinin toplamı olarak tanımlanır. Bölünme oluştuğunda dört çocuklu bir düğüm iki ve üç çocuklu, iki düğüm olur. Bunun anlamı, toplam potansiyel = 2 kadar düşer. Birleştirme oluştuğunda, iki çocuklu iki düğüm üç çocuklu bir düğüm tarafından yer değiştirir. Bunun anlamı, toplam potansiyel 2 0 = 2 kadar düşer. Bu nedenle, her bölme veya birleştirme için, potansiyel iki azalır. Düğümleri bölme ve birleştirmeyi görmezden gelirsek, çocuk sayısı bir yaprağın eklenmesi veya çıkarılması ile değişen sabit sayıda düğüm vardır. Bir düğüm eklerken, potansiyeli en fazla üç artırarak çocuk sayısındaki artış bir olur. Bir yaprağın silinmesi sırasında, potansiyeli en fazla bir artırarak çocuk sayısındaki azalma bir olur ve iki düğüm toplam potansiyellerini en fazla bir artırarak borçlanma işlemine dahil olabilir. Özetlemek gerekirse, her birleştirme ve bölme potansiyeli en az iki azaltır. Birleştirme ve bölmeyi dikkate almayarak, her ekleme veya silme potansiyelin en fazla üç yükselmesine neden olur ve potansiyel her zaman sıfır yada pozitiftir. Bu nedenle, başlangıçta boş bir ağaç üzerinde yapılan m ekleme ya da silme nedeniyle bölünmelerin ve birleştirmelerin sayısı en fazla 3m/2 olur. Böylece bu analizin bir sonucu, ve 2-4 Ağaç lar ve Kırmızı-Siyah Ağaç lar arasındaki ilişki Teorem 9.2 ile verilmiştir. 9.4 Tartışma ve Alıştırmalar Kırmızı-Siyah Ağaç lar ilk olarak Guibas ve Sedgewick [38] tarafından tanıtıldı. Yüksek uygulama karmaşıklığını rağmen bunlar, en sık kullanılan kütüphaneler ve uygulamaların 18 Bu yöntemin diğer uygulamaları için bkz. Önerme 2.2 nin ve Önerme 3.1 in kanıtları. 209

210 bazılarında bulunur. Çoğu algoritmalar ve veri yapıları ders kitapları Kırmızı-Siyah Ağaç ların bazı varyasyonlarını dahil etmişlerdir. Andersson [6] dengeli ağaçların sola-dayanımlı ve kırmızı-siyah ağaçlara benzeyen, ancak herhangi bir düğümünün en fazla bir kırmızı çocuğa sahip olması ek kısıtlamasına sahip bir versiyonunu açıklıyor. Bu ağaçlar 2-4 Ağaç lar yerine 2-3 Ağaç lar gibi davranırlar. Bunlar bu bölümde sunulan Kırmızı-Siyah Ağaç yapısından önemli ölçüde daha kolaydır. Sedgewick [66] sola-dayanan Kırmızı-Siyah Ağaç ların iki versiyonunu açıklıyor. Bunlar 2-4 Ağaç ları yukarıdan-aşağıya bölen ve birleştiren özyinelemeli bir simülasyon kullanır. Bu iki tekniğin kombinasyonu özellikle kısa ve zarif kod yapar. İlgili ve daha eski bir veri yapısı AVL ağacı [3] dır. AVL Ağaç larının yüksekliği-dengelidir: Her düğüm, u, noktasındaki u.left kökenli ağacın yüksekliği ile u.right kökenli altağaç en fazla bir farklıdır. Hemen şunun farkına varmalısınız ki, yaprakları en az sayıda olan yüksekliği h bir F(h) ağacı Fibonacci Yinelemesi ne uyar. F(0) = 1 ve F(1) = 1 olmak üzere, Bunun anlamı, altın oran iken F(h) yaklaşık olarak eşittir. (Daha yüksek doğrulukla, ) Önerme 9.1 kanıtında olduğu gibi, Böylece AVL Ağaç ları Kırmızı-Siyah Ağaç lardan daha küçük yüksekliğe sahiptir. Yükseklik dengeleme ekle(x) ve sil(x) işlemleri sırasında köke giden yolu geri katederek ve her u düğümünde bir u nun sol ve sağ altağaçlarının yüksekliği arasındaki fark iki olduğu takdirde dengelenme işlemi gerçekleştirerek korunabilir. Bkz.Şekil Kırmızı-Siyah Ağaç ların Andersson varyasyonu, Kırmızı-Siyah Ağaç ların Sedgewick varyasyonu, ve AVL Ağaç ları, burada tanımlanan Kırmızı-Siyah Ağaç yapısını uygulamaktan daha kolaydır. Ne yazık ki, bunların hiçbiri dengelenme için harcanan çalışma süresinin 210

211 güncelleme başına O(1) olmasını garanti edemez. Özellikle, o yapılar için Teorem 9.2 nin hiçbir analoğu yoktur. Alıştırma 9.1. Şekil 9.11 de gösterilen Kırmızı-Siyah Ağaç için hangi 2-4 Ağaç oluşturulabilir? Alıştırma 9.2. Şekil 9.11 de gösterilen Kırmızı-Siyah Ağaç içine 13, daha sonra 3,5 ve 3,3 değerlerini eklemeyi gösterin. Alıştırma 9.3. Şekil 9.11 de gösterilen Kırmızı-Siyah Ağaç içinden 11, daha sonra 9 ve 5 değerlerini silmeyi gösterin. Alıştırma 9.4. Oldukça büyük n değerleri için, gösterin ki, 2 log n O(1) yüksekliğinde, n düğümlü Kırmızı-Siyah Ağaç lar vardır Alıştırma 9.5. pushblack(u) ve pullblack(u) işlemlerini dikkate alın. Bu işlemler KırmızıSiyah Ağaç tarafından benzeştirilen 2-4 ağaca ne yapıyor? Alıştırma 9.6. Oldukça büyük n değerleri için, gösterin ki, bir dizi ekle(x) ve sil(x) işlemleri vardır ki, bunların çalıştırılması bizi n düğümden oluşan 2 log n O(1) yüksekliğinde, Kırmızı-Siyah Ağaç lara götürsün? Alıştırma 9.7. Neden Kırmızı-Siyah Ağaç uygulamasında sil(x) yöntemi u.parent = w.parent belirlemesini gerçekleştirir? Zaten bunun splice(w) için yapılan çağrı tarafından yapılması gerekmiyor muydu? Alıştırma 9.8. Bir 2-4 Ağaç ının, T, nl yaprağı ve ni iç düğümü olduğunu düşünün. 1. ni minimum değeri nl cinsinden bir fonksiyonu olarak nedir? 2. ni maksimum değeri nl cinsinden bir fonksiyonu olarak nedir? 3. T ağacı T kırmızı-siyah ağacını temsil ediyorsa, T kaç tane kırmızı düğüme sahiptir? 211

212 Alıştırma 9.9. En az n düğüm ve en çok 2 log n 2 yüksekliğe sahip bir İkili Arama Ağaç ı verilmiştir. Kırmızı ve siyah düğümlerini her zaman siyah-yükseklik ve kırmızı-olmayankenar özelliklerini sağlayacak şekilde renklendirmek mümkün müdür? Eğer öyleyse, soladayanım özelliğini karşılayacak şekilde de yapılabilir mi? Alıştırma Varsayın ki, T1 ve T2 aynı siyah yüksekliğe, h, sahip iki Kırmızı-Siyah Ağaç olsun, ve öyle ki T1 içindeki en büyük değer T2 içindeki en küçük değerden daha küçük olsun. T1 ve T2, tek kırmızı-siyah ağacı içine O(h) zamanda nasıl birleştirilir? Alıştırma Alıştırma 9.10 için hazırladığınız çözümü, farklı siyah yüksekliğe, h1 h2, sahip iki Kırmızı-Siyah Ağaç için tekrar düşünün. Çalışma zamanı O(max (h1, h2)) olmalıdır. Alıştırma ekle(x) işlemi sırasında AVL Ağaç ı (çoğu iki döndürüş içeren) en fazla bir yeniden-dengeleme işlemi gerçekleştirmelidir. (Bkz. Şekil 9.10). Bir AVL Ağacı ve bu ağaç üzerinde yeniden-dengelenme işlemlerinin log n zamanda çalıştığı bir sil(x) işlemi örneği verin. Alıştırma Yukarıda açıklandığı gibi AVL Ağaç larını gerçekleştiren bir AVLAğaç sınıfı uygulayın. Performansını Kırmızı-Siyah Ağaç ın performansı ile karşılaştırın. Hangi uygulamanın bul(x) işlemi daha hızlıdır? Alıştırma Sekme Listesi Sıralı Küme, Günah Keçisi Ağacı, Treap, ve Kırmızı-Siyah Ağaç veri yapılarının Sıralı Küme uygulamalarında gerçekleştirilen bul(x), ekle(x), sil(x) işlemlerinin performanslarını göreceli olarak karşılaştıran bir dizi deney tasarlayın ve uygulayın. Veriler ve silme sıraları rasgele ve sıralı olan birden fazla test senaryosu hazırlayın. 212

213 Bölüm 10 Yığınlar Bu bölümde, Öncelik Kuyruğu veri yapısının son derece yararlı iki uygulaması tanıtılıyor. Bu yapıların her ikisinde de Yığın adında İkili Ağaç ın "Dağınık Yığın" anlamına gelen özel bir türü incelemeye alınmıştır. İkili Arama Ağaç larının tersi olarak, İkili Ağaç lara esneklik kazandırılmıştır. Aynı verinin geliş sırasına göre farklı düğüm lokasyonlarında depolanmaması analizimizi kolaylaştırır. Yığın uygulamasının birincisi bir dizi kullanır. Çok hızlı uygulama olarak bilinen en hızlı sıralama algoritmalarından biri yığında sıralamaktır. (Bkz. Bölüm ). İkinci uygulamada Öncelik Kuyruğu nun önceliğinden yararlanarak bir meld(d) işlemi ikinci bir öncelik kuyruğunun elemanları birleştirmekte kullanılmıştır İkili Yığın: Bir Örtülü İkili Ağaç Öncelik Kuyruğu dört yüz yıldan daha eski bir tekniğe dayanır. Eytzinger yöntemi bir dizi kullanarak enine-aramayla İkili Ağaç ı gerçekleştirir (Bölüm 6.1.2). Bu şekilde, kök, 0 konumunda depolanır. kökün sol çocuğu 1 konumunda saklanır, 2 pozisyonunda kökün sağ çocuğu, ve kökün sol çocuğun sol alt böylece 3 de depolanır (Bkz.Şekil 10.1). Yeterince büyük bir ağaca Eytzinger yöntemini uygularsanız, bazı desenler ortaya çıkar. i inci endeksteki düğümün sol alt çocuğunda left(i) = 2i + 1 yer almaktadır ve i inci endeksteki düğümün sağ alt çocuğunda right(i) = 2i + 2 yer almaktadır. i endeksindeki düğümün menşei parent(i) = (i 1 )/2. 213

214 İkili Yığın elemanlarını yığın-sıralı yapan bir İkili Ağaç ın temsilinde kullanılan teknik açıklanırken başlangıç noktası i = 0, kök değeri dışında herhangi bir i çocuğu için saklanan değerin,, parent(i) menşei de depolanmış değerden daha küçük olmaması olarak belirtilmiştir. Bunu takiben, Öncelik Kuyruğu'ndaki en küçük değerin 0 pozisyonda (kök) saklandığını çıkarsaymak kolaydır. n elemanlı İkili Yığın ın elemanlarını a dizisinde depolayabiliriz: ekle(x) işlemi uygulaması kolaydır. Tüm dizi tabanlı yapılarında olduğu gibi dolu olduğunu kontrol ederiz (a.length = n edilerek), ve eğer öyleyse, a bir eleman büyütülür. Sonra, bir 214

215 a[n] konumuna x yerleştirmek için, n bir artırılır. Bu noktada, geriye tüm bu yığın özelliğini korumayı sağlamak kalır. x, ebeveyninden daha küçük olana kadar defalarca x i ebeveyni ile yer değiştirerek bunu yapabiliriz. (Bkz. Şekil 10.2) Yığının en küçük değerini silen remove() işlemi uygulaması biraz yanıltıcıdır. Küçük değerin kökte olduğu biliniyor, ancak onu sildikten sonra yığın özelliğini korumayı sağlamak için eleman diğer değerlerle tekrar yığına kazandırılmalıdır. Bunu yapmak için en kolay yol, a[n - 1] değerini kök ile yer değiştirmektir, o değer silinir ve n bir azaltılır. Ne yazık ki, kökteki yeni eleman şimdi en küçük eleman olmaz, bu nedenle doğru yeri bulmak için elemanın sıralamada alt kademede bulunan iki çocuğu ile defalarca karşılaştırılması uygun olacaktır. Karşılaştırma sonucunda eleman üçünün en küçüğü ise, silme işlemi sona erer. Aksi takdirde, onun iki çocuğu ile bu eleman alt kademelere doğru yer değiştirir. Diğer dizi-bazlı yapılar, Önerme 2.1 deki amortize argümana dayanarak yeniden_oluştur(u) işlemi için yapılan çağrıların çalışma zamanını dikkate almamıştı. ekle(x) ve sil(x) işlemleri için yapılan çağrıların çalışma zamanı (içsel) İkili Ağaç ın yüksekliğine bağlıdır. Tam İkili 215

216 Ağaç ta son seviye dışında her seviye olası maksimum depolama kapasitesindedir. Bu nedenle, ağacın yüksekliği h ise, o zaman en az 2h düğümü vardır. Matematiksel anlamda bu, Bu denklemin her iki tarafının logaritması alındığı takdirde, Bu nedenle, ekle(x) ve sil(x) işleminin çalışma zamanı O(log n) olur. 216

217 217

218 Özet Teorem Aşağıdaki teorem İkili Yığın performansını özetler: Bir İkili Yığın, Öncelik Kuyruğu arayüzünü uygular. yeniden_oluştur(u) işlemi için yapılan çağrıların maliyeti dikkate alınmayarak, ekle (x), sil (x) ve bul(x) işlemleri İkili Yığın tarafından işlem başına O(log n) zamanda desteklenir. Ayrıca, boş bir İkili Yığın ile başlandığında, ekle (x) ve sil (x) işlemleri toplam m defa çağrılırsa, tüm yeniden_oluştur (u) çağrıları için gerekli toplam çalışma süresi O(m) olur Karışık Yığın: Rasgele Karışık Yığın Bu bölümde, yığın-sıralı İkili Ağaç yapısı üzerine gerçekleştirilen Öncelik Kuyruğu nun bir uygulaması olan Karışık Yığın tanıtılıyor. Bununla birlikte, İkili Ağaç tan farklı olarak İkili Ağaç tamamen elemanların sayısı ile tanımlandığı halde, İkili Ağaç taki düğümlerin lokasyonu üzerinde herhangi bir kısıtlama yoktur. Karışık Yığın için ekle(x) ve sil() işlemleri uygulanırken merge(h1, h2) işleminden faydalanılmıştır. İşlem iki ayrı yığın düğümünü, h1, h2, birleştirmek üzere alır. h1 kökenli altağacın tüm elemanlarını ve h2 kökenli altağacın tüm elemanlarını yığının kökü olan düğümle birlikte döndürür. merge (h1, h2) işleminin özyinelemeli olarak tanımlanmış olması programcıya birtakım kolaylık sağlar. (Bkz. 10.4) Boş küme ile birleştirme durumunda, h1 veya h2, biri yada ikisi, nil olmalıdır. Bu durumda işlem sırasıyla, h2 veya h1 döndürür. Aksi takdirde, varsayalım h1.x h2.x. Kök h1.x olduğu takdirde, h2, özyinelemeli olarak h1.left veya h1.right ile birleştirilmelidir. h2 yi birleştirmek için h1.left mi? h1.right mi? sorusunun cevabına karar vermek için rasgelelik kullanılır ve yazı tura atılır. 218

219 h1.x > h2.x koşulu geçerliyse, ekstra kod yazmaya gerek yoktur. Aynı kodu küçük değişikliklerle, h1 ve h2 rollerini tersine çevirerek rahatlıkla işletebilirsiniz. 219

220 h1 ve h2 elemanlarının toplam sayısına n dersek merge (h1, h2) işleminin beklenen çalışma zamanı O(log n) olur. Bir sonraki bölüm bunun analizini gösteriyor. merge (h1, h2) işleminden faydalandığımız takdirde, ekle(x) işlemini uygulamak kolaydır. x değerini içeren yeni bir u düğümü kök kabul ederek oluştururuz. Sonra yığını kök u ile birleştiririz. Beklenen çalışma zamanı O(log n) = O(log (n+1)) olur. remove() işlemi fonksiyonu benzerdir ve uygulaması kolaydır. Silmek istediğimiz düğümü kök kabul edersek, kökün iki çocuğunu birleştiririz ve ortaya çıkan yığın istediğimiz sonucu bize verir. Beklenen çalışma zamanı O(log n) olur. Karışık Yığın, beklenen çalışma zamanı O(log n) olan başka işlemleri de uygulamamıza izin veriyor: 220

221 sil(u) : u em(h) : Karışık Yığın, h, içindeki düğümü yığından silinir (u.x anahtarını da siler). tüm elemanlar bu yığına eklenir, h elemanları silinerek nil olur. Bu işlemlerin her biri için merge(h1,h2) işlemi sabit sayıda tekrar tekrar çalıştırılırsa, beklenen toplam çalışma zamanı her bir merge için O(log n) olarak hesaplanmalıdır merge(h1, h2) Analizi merge(h1, h2) analizinde İkili Ağaç üzerinde rasgele yürüyüş tekniği kullanılıyor. İkili Ağaç rasgele yürüyüşü ağacın kökünden başlar. Rasgele yürüyüşün, her aşamasında, yazı tura atılır ve sonucuna bakarak bulunduğumuz düğümün sol veya sağ çocuğuna doğru ilerlemeye karar veririz. Ağacın sonuna geldiğimizde (bulunduğumuz düğüm nil ise) yürüyüş biter. Aşağıdaki önermenin dikkat çekici yönü, İkili Ağaç ta depolanan değerlerin düğümlerin lokasyonuna bağlı olmamasıdır. Önerme n düğümü olan İkili Ağaç a uygulanan rasgele yürüyüşün beklenen uzunluğu en fazla log(n+1) olur. Kanıt. n üzerinde tümevarım yöntemiyle kanıtlanacak. Taban durumunda, n = 0, ve yürüyüş uzunluğu 0 = log n + 1 kabul edilir. Sonucun tüm negatif olmayan tamsayılar n < n için doğru olduğunu varsayalım. Kökün sol alt ağacının büyüklüğünün n1 olduğunu gösterelim, böylece n2 = n n1 1 kökün sağ altağacın boyutudur. Yürüyüş kökten başlar, bir adım sonra n1 veya n2 boyutlarında olan altağaç ile devam eder. Tümevarım hipotezimiz yürüyüşün beklenen uzunluğunun 221

222 olduğunu bize söylüyor, çünkü n1 ve n2, her ikisi de n den küçüktür. log fonksiyonu içbükey özelliğe sahip olduğundan n1 = n2 = (n - 1) / 2 olduğunda, E[W] en büyük olur. Bu nedenle, rasgele yürüyüş tarafından atılan adımların beklenen sayısı olur. Konu dışında kalsa da okuyucuya belirtmemiz gereken bir açılım da Önerme 10.1 nin kanıtını entropi yöntemi ile yapmaktır. Önerme 10.1 için Bilgi Teorik Kanıt. i'inci dış düğümün derinliği di ile gösterilsin. n düğümlü İkili Ağaç ın n+1 dış düğüme sahip olduğunu hatırlayın. i inci dış düğüme ulaşan rasgele yürüyüşün olasılığı tam olarak, olduğu için rasgele yürüyüşün beklenen uzunluğu ile verilir. Bu denklemin sağ tarafı n+1 eleman üzerinde bir olasılık dağılımının entropisi olarak kolaylıkla tanınabilir. n+1 eleman için entropik değer log(n+1) aşmaz, bu kanıtı tamamlar. Rasgele yürüyüşler bu sonuçla birlikte, merge(h1, h2) işleminin çalışma zamanının O(log n) olduğunu kanıtlamaya da yarar. Önerme n1 ve n2 düğümlü içeren iki yığının kökleri sırasıyla h1 ve h2 ise, o zaman merge(h1, h2) için beklenen çalışma süresi, n = n1 + n2 iken, O(log n) olur. 222

223 Kanıt. h1 yada h2 kökenli yığınlar için merge algoritmasının her adımında, rasgele yürüyüş uygulanır. Bu iki rasgele yürüyüş bittiğinde (h1 = null yada h2 = null) algoritma sona erer. Bu nedenle, merge algoritması tarafından gerçekleştirilen adımların beklenen sayısı en fazla olur Özet Aşağıdaki teorem Karışık Yığın performansını özetler: Teorem Karışık Yığın, Öncelik Kuyruğu arayüzünü uygular. ekle (x), sil () işlemleri Karışık Yığın tarafından işlem başına O(log n) beklenen zamanda desteklenir Tartışma ve Alıştırmalar İkili Ağaç ın bir dizi yada liste olarak içsel gösterimi ilk olarak Eytzinger [27] tarafından önerilmiştir. Kendisi asil ailelerin soy ağaçlarını içeren kitaplarda bu temsili kullanmıştır. Burada anlatılan İkili Yığın veri yapısı ilk olarak Williams [78] tarafından tanıtıldı. Burada açıklanan Rasgele Karışık Yığın veri yapısı ilk olarak Gambin ve Malinowski [34] tarafından önerilmiştir. Diğer Karışık Yığın uygulamaları vardır: Hiçbiri Karışık Yığın yapısı kadar basit olmamasına rağmen, sol-odaklı yığınlar [16, 48, Bölüm 5.3.2], binom yığınları [75], Fibonacci yığınları [30], eşleştirme yığınları [29], ve çarpık yığınlar [72]. Yukarıdaki yapıların bazıları decreasekey(u, y) işlemini destekler. Bu işlem u düğümünde saklanan değeri y olarak düşürerek belirler (y x önkoşuldur). Yukarıdaki yapıların çoğunda, u düğümünü silerek ve yeni bir y değerini ekleyerek bu işlem O(log n) zamanda desteklenir. Bununla birlikte, bu yapıların bir kısmı decreasekey (u, y) işlemini daha etkili uygulayabilir. Özellikle, decreasekey(u, y) Fibonacci yığınları için O(1) amortize zaman ve eşleştirme yığınlarının [25] özel bir sürümü için O(log log n) amortize zaman alır. Bu daha verimli 223

224 decreasekey(u, y) işleminin, Dijkstra'nın en kısa yol algoritması [30] dahil, grafik algoritmalarını hızlandıran uygulamaları bulunmaktadır. Alıştırma Şekil 10.2 sonunda gösterilen İkili Ağaç a 7 ve daha sonra 3 değerlerinin eklenmesini gösterin. Alıştırma Şekil 10.2 sonunda gösterilen İkili Ağaç tan sonraki iki değerin (6 ve 8) silinmesini gösterin. Alıştırma İkili Ağaç ta depolanan bir a[i] değerini silen sil(i) yöntemini uygulayın. Bu yöntemin çalışma zamanı O(log n) olmalıdır. Bu yöntemin yararlı olmasının neden olası olmadığını açıklayın. Alıştırma Bir İkili Ağaç ın genellemesi olan d-ağaç ında her iç düğümün d çocuğu vardır. Tam d-li Ağaç lar, dizileri kullanarak Eytzinger yönteminin kullanılmasıyla gösterilebilir. Bir i endeksi verildiğinde i'nin menşei endeksini ve i'nin d çocuğunu d-li Ağaç gösteriminde belirleyecek denklemler bulmaya çalışın. Alıştırma Alıştırma 10.4 te öğrendiklerinizi kullanarak, İkili Yığın ın d-li genelleştirmesi olan D-li Yığın tasarlayın ve uygulayın. D-li Yığın üzerindeki işlemlerin çalışma zamanlarını analiz edin ve D-li Yığın uygulamasının performansını burada verilen İkili Yığın uygulamasının performansına karşı test edin. Alıştırma Şekil 10.4 te gösterilen, h1, Karışık Yığın ına 17 ve daha sonra 82 değerlerinin eklenmesini gösterin. Gerektiğinde rasgele biti örneklemek için madeni para kullanın. Alıştırma Şekil 10.4 te gösterilen, h1, Karışık Yığın ından sonraki iki değerin (4 ve 8) silinmesini gösterin. Gerektiğinde rasgele biti örneklemek için madeni para kullanın. Alıştırma Bir Karışık Yığın dan u düğümünü kaldıran sil(u) yöntemini uygulamak. Bu yöntemin beklenen çalışma zamanı O(log n) olmalıdır. 224

225 Alıştırma İkili Yığın veya Karışık Yığın içinde depolanan ikinci en küçük değerin sabit zamanda nasıl bulunacağını gösterin. Alıştırma İkili Yığın veya Karışık Yığın içinde depolanan k nci en küçük değerin O(k log k) zamanda nasıl bulunacağını gösterin (İpucu: İkinci bir yığın yardımcı olarak kullanılabilir). Alıştırma Varsayın ki, toplam uzunluğu n olan, k adet sınıflandırma-listesi verilmiştir. Bir yığın kullanarak bunları O(n log k) zamanda sadece tek adet sıralı liste içine nasıl yerleştireceğimizi gösterin (İpucu: k = 2 iken başlamak öğretici olabilir.) 225

226 Bölüm 11 Sıralama Algoritmaları Bu bölümde, n elemanlı bir kümenin sıralaması ile ilgili algoritmalar tanıtılıyor. Bu veri yapıları üzerine bir kitap için garip bir konu gibi görünebilir, ama buraya dahil edilmesi için birçok iyi nedeni vardır. En belirgin nedeni bu sıralama algoritmalarının ikisi (hızlı-sıralama ve dikey-sıralama) daha önce detaylarıyla incelediğimiz veri yapılarının ikisi ile ilişkilidir (sırasıyla, rasgele ikili arama ağaçları ve yığınlar). Bu bölümün ilk kısmı yalnızca karşılaştırmalara dayanan sıralama algoritmalarını tartışıyor ve O(n log n) zamanda çalışan üç algoritma sunuyor. Her üç algoritmanın da asimptotik en iyi olduğu ortaya çıkmıştır; sadece karşılaştırma kullanan hiçbir algoritma en kötü veya ortalama durumda bile kabaca n log n karşılaştırmadan daha azını yapmanın önüne geçememiştir. Devam etmeden önce, dikkat etmeliyiz ki, önceki bölümlerde sunulan Sıralı Küme veya Öncelik Kuyruğu uygulamalarının herhangi biri O(n log n) zamanda çalışan bir sıralama algoritması elde etmek için kullanılabilir. Örneğin, bir İkili Yığın veya Karışık Yığın üzerinde n ekle(x) işlemini takip eden n sil() işlemini gerçekleştirerek n elemanı sıralayabiliriz. Alternatif olarak, İkili Arama Ağacı veri yapılarının herhangi biri üzerinde n ekle(x) işlemini kullanır ve daha sonra elemanları sıralı-halde elde etmek için bir içsel-sıra gezintisi (Alıştırma 6.8) gerçekleştirebiliriz. Ancak her iki durumda da, hiçbir zaman tam olarak kullanılmayan bir yapı oluşturmak için bir sürü yüke katlanmak zorunda kalınmaktadır. Bu nedenle sıralama, mümkün olan en hızlı, basit ve alan-verimli direkt yöntemler geliştirmemizi gerekli kılan çok önemli bir sorun olarak ortaya çıkmaktadır. Bu bölümün ikinci kısmı, karşılaştırmalar dışında kalan tüm diğer işlemlerin bahis dışı kaldığını gösteriyor. Nitekim, dizi endekslemesini kullanarak, {0,.., nc 1} aralığında n tamsayı kümesini O(cn) zamanda sıralamak mümkündür. 226

227 11.1 Karşılaştırmaya-Dayalı Sıralamalar Bu bölümde, üç sıralama algoritmasını tanıtılıyor: birleştirerek-sıralama, hızlı-sıralama ve dikey-sıralama. Bu algoritmaların her biri girdi olarak a dizisini alır ve elemanlarını artansırada O(n log n) (beklenen) zamanda sıralar. Bu algoritmaların hepsi karşılaştırmayadayalıdır. İkinci argüman, c, compare(a, b) yöntemini uygulayan bir Karşılaştırıcı dır. Bu algoritmalar hangi tür veriyi sıraladığını önemsemez; veri üzerinde yaptıkları tek işlem compare(a, b) yöntemini kullanarak yapılan karşılaştırmadır. Bölüm ten hatırlamalısınız ki, a < b ise compare(a, b) negatif bir değer döndürür, a > b için pozitif bir değer döndürür, ve a = b ise sıfır döndürür Birleştirerek-Sıralama Birleştirerek-sıralama algoritması klasik bir özyinelemeli böl ve yönet örneğidir: a uzunluğu en fazla 1 ise, o zaman a zaten sıralanmıştır, bu yüzden hiçbir şey yapmayız. Aksi takdirde, a iki parçaya bölünür, a0 = a[0],..., a[n/2 1] ve a1 = a[n/2],..., a[n 1]. Özyinelemeli olarak a0 ve a1 sıralanır, ve sonra (şimdi sıralı olan) a0 ve a1 dizileri tam sıralı bir a dizisini oluşturacak şekilde birleştirilir. Bir örnek Şekil 11.1 'de gösterilmektedir. 227

228 İki sıralı diziyi, a0 ve a1, birleştirmek, sıralamaya göre oldukça kolaydır. Her seferinde bir elemanı a ya ekleriz. a0 veya a1 boşsa, o zaman diğer (boş olmayan) dizideki sonraki elemanları ekleriz. Aksi takdirde, a0 içindeki sonraki elemanın ve a1 içindeki sonraki elemanın en küçüğünü alır ve bunu a dizisine ekleriz: Dikkat etmelisiniz ki, merge(a0, a1, a, c) algoritması a0 veya a1 dizilerindeki elemanları tüketmeden önce en fazla n 1 karşılaştırma yapar. 228

229 Birleştirerek-sıralama için gerekli çalışma zamanını anlamak için en kolay yol, özyineleme ağacını düşünmek olacaktır. Şimdilik n in ikinin üssü olduğunu varsayın, öyle ki log n bir tamsayı iken n = 2log n olsun. Şekil 11.2 e bakın. Birleştirerek-sıralama n elemanı sıralama problemini, her biri n/2 elemanı sıralayan iki problem haline dönüştürür. Bu iki altproblem yine daha sonra iki problem haline dönüşür, her biri n/4 elemandan oluşan dört altproblem elde edilir. Bu dört altproblem her biri n/8 elemandan oluşan sekiz altproblem haline dönüşür, ve benzeri. Bu işlemin en son alt kısmında, her birinin boyutu 2 olan n/2 alt problem, her birinin boyutu 1 olan n probleme dönüştürülür. Her n/2i boyutunda altproblem için veri birleştirme ve kopyalama için harcanan zaman O(n/2i) olur. n/2i boyutunda 2i altproblem olduğu için 2i boyutunda problemler üzerinde çalışılan toplam zaman, özyinelemeli çağrılar sayılmaksızın, olur. Bu nedenle, birleştirerek-sıralama için harcanan toplam zaman olur. Aşağıdaki teoremin kanıtı önceki analize dayanmaktadır, ama n için 2 in üssü değil iken biraz daha dikkatli olunmak zorundadır. 229

230 Teorem mergesort(a, c) algoritması O(n log n) zamanda çalışır ve en çok n log n karşılaştırma gerçekleştirir. Kanıt. n üzerine tümevarım yöntemiyle kanıtlanacak. Temel durum, n = 1, önemsiz kabul ediliyor. Uzunluğu 0 ya da 1 olan bir dizi sunulduğunda, algoritma herhangi bir karşılaştırma yapmadan sadece diziyi döndürür. Toplam uzunluğu n olan iki sıralı listeyi birleştirmek en fazla n 1 karşılaştırma yapmayı gerektirir. n uzunluğunda bir a dizisi üzerinde mergesort(a, c) tarafından gerçekleştirilen karşılaştırmaların maksimum sayısı C(n) ile belirtilsin. n çift ise, o zaman iki altproblem için tümevarım hipotezini uygulayarak, elde ederiz. n tek olduğu zaman durum biraz daha karmaşıktır. Bu durumda, doğrulanması kolay iki eşitsizlik kullanıyoruz: her x 1 için ve her x ½ için. (11.1) eşitsizliği log(x) + 1 = log(2x) olması gerçeğinden ileri geliyor. (11.2) eşitsizliği log fonksiyonunun içbükey özelliğe sahip olması gerçeğinden ileri geliyor. Elimizdeki bu araçlar ile, tek sayıdaki n için, 230

231 olur Hızlı-Sıralama Hızlı-sıralama algoritması diğer bir klasik böl ve yönet algoritmasıdır. İki altproblemi çözdükten sonra birleştiren birleştirerek-sıralamanın aksine hızlı-sıralama, çalışmalarının hepsini açık ve belirgin bir şekilde yapar. Hızlı-sıralamanın tanımlanması oldukça kolaydır: a içinden rasgele bir pivot elemanı, x, seçilir; x den küçük elemanların oluşturduğu küme, x e eşit elemanların oluşturduğu küme, ve x den büyük elemanların oluşturduğu küme olmak üzere a üç parçaya bölünür, ve nihayet, özyinelemeli olarak birinci ve üçüncü kümeler sıralanır. Bir örnek Şekil 11.3 'de gösterilmiştir. Tüm bunlar yerli yerinde yapılır, böylece sıralanacak altdizilerin kopyalarını yapmak yerine, quicksort(a, i, n, c) yöntemi sadece a[i],, a[i + n 1] altdizisini sıralar. Başlangıçta, bu yöntem quicksort(a, 0, a.length, c) argümanları ile çağrılır. Hızlı-sıralama algoritmasının kalbinde yerinde bölümleme algoritması yatar. Bu algoritma, herhangi bir ekstra alan kullanmadan, a elemanlarını yer değiştirerek p ve q endekslerini hesaplar; öyle ki 231

232 Kodda while döngüsü tarafından yapılan bu bölümleme, ilk ve son koşulu korumak şartıyla p nin tekrarlanarak artırılmasıyla ve q nun azaltılmasıyla çalışır. Her adımda, j pozisyonundaki eleman ya öne taşınır, ya olduğu yerde sola kaydırılır, yada geriye taşınır. İlk iki durumda j artırılırken, son durumda iken j artırılmaz, çünkü j pozisyonundaki yeni eleman henüz işlenmemiştir. 232

233 Hızlı-sıralama Bölüm 7.1 de anlatılan Rasgele İkili Arama Ağaç ları ile çok yakından ilgilidir. Aslında, hızlı-sıralamaya verilen girdi n birbirinden farklı elemandan oluşmuş ise, o zaman hızlı-sıralamanın özyineleme ağacı bir Rasgele İkili Arama Ağacı dır. Bunu görmek için, hatırlamanız gerekiyor ki, bir Rasgele İkili Arama Ağacı nı oluşturacağınız zaman yaptığımız ilk şey, rasgele bir x elemanını seçmek ve bunu ağacın kökü yapmaktı. Bundan sonra, her bir eleman sonunda x ile karşılaştırılmıştı, küçük elemanlar sol altağacın içine giderken, daha büyük elemanlar sağa doğru gitmişti. Hızlı-sıralamada rasgele bir x elemanı seçeriz ve hemen her şeyi x ile karşılaştırırız, daha küçük elemanları dizinin başına koyarız, ve daha büyük elemanları dizinin sonuna koyarız. Rasgele İkili Arama Ağacı özyinelemeli olarak kökün sol altağacına daha küçük elemanları, ve kökün sağ altağacına daha büyük elemanları eklerken, hızlı-sıralama özyinelemeli olarak dizinin başlangıcını ve dizinin sonunu sıralar. Rasgele İkili Arama Ağaç lar ve hızlı-sıralama arasındaki yukarıdaki benzerlikler, Önerme 7.1 i kullanarak hızlı-sıralama hakkında bir bildiri yapabileceğimiz anlamına gelir. Önerme Hızlı-sıralama 0,, n 1 içindeki tamsayıları içeren bir diziyi sıralamak için çağrıldığında, i elemanının pivot eleman ile karşılaştırılmasının beklenen sayısı en fazla Hi+1 + Hn-i olur. Harmonik sayıların küçük bir özetlemesi bize hızlı-sıralamanın çalışma zamanı ile ilgili aşağıdaki teoremi verir: Teorem Hızlı-sıralama n birbirinden farklı elemanı içeren bir diziyi sıralamak için çağrıldığında, yapılan karşılaştırmaların beklenen sayısı en fazla 2n ln n + O(n) olur. Kanıt. n birbirinden farklı eleman sıralanırken hızlı-sıralama tarafından yapılan karşılaştırmaların sayısı T olsun. Önerme 11.1 ve beklentinin doğrusallık özelliği kullanılarak 233

234 elde edilir. Teorem 11.3 sıralanan tüm elemanların birbirinden farklı olduğu durumu anlatıyor. Girdi, a, dizisi, yinelenen elemanları içeriyorsa, hızlı-sıralamanın beklenen çalışma süresi daha kötü değildir ve hatta daha da iyi olabilir; her zaman yinelenen bir eleman, x, pivot olarak seçilir, x in tüm oluşumları birbiriyle gruplanır, ve iki altproblemin hiçbirinde yer almazlar. Teorem quicksort (a, c) yöntemi O(n log n) beklenen zamanda çalışır ve gerçekleştirdiği karşılaştırmaların beklenen sayısı en fazla 2n ln n + O(n) olur. 234

235 Yığın-Sıralama Yığın-sıralama algoritması diğer bir yerinde-sıralama algoritmasıdır. Hatırlayın ki, İkili Yığın veri yapısı tek dizi kullanarak bir yığını gösteriyordu. Yığın-sıralama algoritması girdi, a, dizisini bir yığına dönüştürür, ve daha sonra art arda minimum değeri ayıklar. Daha özel olarak, bir yığın, a, dizisi içindeki n elemanı en küçük değer kökte, a[0], saklanmak üzere, a[0],, a[n 1] lokasyonlarında depolar. a bir İkili Yığın a dönüştürüldükten sonra, yığın sıralama algoritması tekrar tekrar a[0] ile a[n 1] i yer değiştirerek n i bir azaltır, ve trickledown(0) çağrılır. Böylece a[0],..., a[n - 2], bir kere daha geçerli bir yığını gösterir. Bu süreç sona erdiğinde (çünkü, n = 0), a elemanları azalan sırada depolanır, a sıralaması ters çevrilerek nihai sıralama kriteri elde edilmelidir.19 Şekil 11.4 örnek bir heapsort(a, c) çalıştırmasını gösteriyor. Yığın-sıralamada anahtar kurucu altprogram, sıralı olmayan bir a dizisini bir yığın haline dönüştürmelidir. Defalarca İkili Yığın, ekle(x) yöntemini çağırarak bunu O(n log n) zamanda yapmak kolay olurdu ama aşağıdan-yukarıya algoritma kullanarak daha iyi hale gelebilir. Hatırlayın ki, bir İkili Yığın içinde a[i] nin çocukları a[2i + 1] ve a[2i + 2] konumlarında saklanır. her bir elemanlarının çocuğu yoktur anlamına gelir. Diğer bir deyişle, boyutu 1 olan bir alt yığındır. Şimdi, geriye doğru çalışırsak, her için trickledown(i) çağrısı yapabiliriz. Bu çalışır, çünkü trickledown(i) çağrısı yapıldığı zaman a[i] nin her iki çocuğu, bir altyığının köküdür, böylece trickledown(i) çağrısı a[i] yi kendi altyığınının kökü yapar. 19 Algoritma alternatif bir compare(x, y) fonksiyonunu yeniden tanımlayabilir, böylece yığın sıralama algoritması doğrudan artan sırada elemanları düzenleyebilir. 235

236 Aşağıdan-yukarıya strateji ile ilgili ilginç bir şey n defa ekle(x) çağırmaktan daha etkili olmasıdır. Bunun için fark etmelisiniz ki, n/2 eleman için, hiçbir iş yapmıyoruz, n/4 eleman için a[i] kökenli ve yüksekliği bir olan bir altyığın üzerine trickledown(i) çağrısı yapıyoruz, n/8 eleman için yüksekliği iki olan bir altyığın üzerine trickledown(i) çağrısı yapıyoruz, ve benzeri. trickledown(i) tarafından yapılan çalışma bir a[i] kökenli altyığının yüksekliği ile orantılı olduğu için, bu yapılan toplam iş en fazla olur. Sondan ikinci eşitliği, toplamını, ilk defa yazı gelene kadar atılan yazı-turanın beklenen sayısına eşit olduğunu tanıyarak ve Önerme 4.2 yi uygulayarak oluşturduk. Aşağıdaki teorem heapsort(a, c) performansını açıklıyor. Teorem heapsort(a, c) yöntemi O(n log n) zamanda çalışır ve en fazla 2n log n + O(n) karşılaştırma gerçekleştirir. Kanıt. Algoritma üç adımda çalışır: (1) a dizisinin bir yığın içine dönüştürülmesi (2) a içinden art arda minimum elemanın çıkarılması, (3) a elemanlarının ters çevrilmesi. Adım 1 in çalışması için, O(n) zaman gerektiği ve O(n) karşılaştırma gerçekleştirdiğini az önce tartışmıştık. Adım 3, O(n) zaman alır ve hiçbir karşılaştırma yapmaz. Adım 2, trickledown(0) 236

237 için n çağrı gerçekleştirir. i'inci böyle bir çağrı n - i büyüklüğünde bir yığın üzerinde çalışır ve en fazla 2log (n - i) karşılaştırma gerçekleştirir. i üzerinden bunların toplanması, sonucuyla, üç adımın her birinde yapılan karşılaştırmaların sayısını ekleyerek kanıt tamamlanır Karşılaştırmaya Dayalı Sıralama için Alt-Sınır Şimdiye kadar gördüğümüz karşılaştırmaya-dayalı sıralama algoritmalarının her biri O(n log n) zamanda çalışıyordu. Artık daha hızlı algoritmaların var olduğu ilgimizi çekmelidir. Bu soruya verilecek kısa cevap hayırdan ibarettir. a elemanları sadece karşılaştırmaya dayalı işlemlere izin veriyorsa, o zaman hiçbir algoritma kabaca n log n karşılaştırma yapmayı önleyemez. Bunu kanıtlamak zor değildir, ama biraz sebat gerektirir. Sonuçta, gerçeğinden ileri geliyor (Bu gerçeğin kanıtlanmasını Alıştırma soruyor). İlk olarak dikkatimizi n belirli bir sabit değeri için birleştirerek-sıralama ve yığın-sıralama gibi deterministik algoritmalara odaklayarak başlayacağız. Birbirinden farklı n elemanı sıralamak için böyle bir algoritmanın kullanıldığını varsayın. Alt sınırı kanıtlamanın yolunda anahtar rol oynayan şu gözlemdir ki, bir sabit, n, değerine sahip deterministik bir algoritma için karşılaştırılan ilk eleman çifti her zaman aynıdır. Örneğin, heapsort(a, c) içinde n çift ise trickledown(i) a[n 1] için yapılan ilk çağrıda i = n/2 1 ve ilk karşılaştırma da a[n/2 1] ve elemanları arasında gerçekleştirilmektedir. 237

238 Tüm girdi elemanları birbirinden farklı olduğu için, bu ilk karşılaştırmanın sadece iki olası sonucu vardır. Algoritma tarafından yapılan ikinci karşılaştırma birinci karşılaştırmanın sonucuna bağlı olabilir. Üçüncü karşılaştırma böylece ilk ikisinin sonuçlarına bağlı olabilir, ve benzeri. Bu nedenle, herhangi bir deterministik, karşılaştırmaya-dayalı sıralama algoritması köklü bir ikili karşılaştırma ağacı olarak görülebilir. Bu ağacın her bir, u, iç düğümü u.i ve u.j endeks çifti ile etiketlenmiştir. a[u.i] < a[u.j] ise algoritma sol alt ağaca doğru ilerler, aksi takdirde sağ alt ağaca doğru ilerler. Bu ağacın her, w, yaprağı 0,, n 1 aralığındaki bir w.p[0],, w.p[n 1] permütasyonu ile etiketlenmiştir. Bu permütasyon, karşılaştırma ağacı bu yaprağa ulaşırsa, a yı sıralamak için gereklidir. Yani, Boyutu, n = 3 olan, bir dizi için karşılaştırma ağacının örneği Şekil 11.5 te gösterilmiştir. Bir sıralama algoritması için karşılaştırma ağacı bize algoritma hakkında her şeyi anlatır. Bu tam olarak birbirinden farklı, n, elemana sahip herhangi bir girdi dizisi, a, için yapılacak karşılaştırmaların birbiri ardı sıra dizilimlerini ve algoritmanın a yı sıralamak için onu nasıl yeniden düzenleyeceğini söyler. Sonuç olarak, karşılaştırma ağacı en az n! yapraktan oluşmalıdır; eğer değilse, o zaman aynı yaprağa yol açan (giden) iki farklı permütasyon mevcuttur; bu nedenle algoritma bu permütasyonların en az birini doğru olarak sıralamaz. Örneğin, Şekil 11.6 'deki karşılaştırma ağacı, 4 < 3! = 6 yaprağa sahiptir. Bu ağacı incelersek, görüyoruz ki, iki girdi dizisi 3, 1, 2 ve 3, 2, 1 en sağdaki yaprağa götürür. 3, 1, 2 girdisinde yaprak doğru çıktı üretir a[1] = 1, a[2] = 2, a[0] = 3. Ancak, 3, 2, 1 girdisi üzerinde bu düğüm 238

239 hatalı çıktı üretir a[1] = 2, a[2] = 1, a[0] = 3. Bu tartışma karşılaştırmaya dayalı algoritmalar için birincil alt sınıra yol açar. Teorem Herhangi bir deterministik karşılaştırmaya dayalı, A, sıralama algoritması ve herhangi bir n 1 tamsayısı için, n uzunluğunda öyle bir, a, girdi dizisi vardır ki, A nın a dizisini sıralamak için gerçekleştirdiği karşılaştırma sayısı en az log(n!)= n logn - O(n) olur. Kanıt. Yukarıdaki tartışma ile, A tarafından tanımlanan karşılaştırma ağacı en az n! yaprak içermektedir. Kolay bir tümevarım kanıtı gösteriyor ki, k yapraklı herhangi bir ikili ağaç en az log k yüksekliğe sahiptir. Bu nedenle, A nın karşılaştırma ağacında derinliği en az log(n!) olan bir w yaprağı vardır ve bu yaprağa yol açan (giden) bir girdi, a, dizisi vardır. Girdi, a, dizisi üzerinde A en az log(n!) karşılaştırma gerçekleştirir. Teoremi 11.5 birleştirerek-sıralama ve yığın-sıralama gibi deterministik algoritmalar içindir, ama hızlı-sıralama gibi randomize algoritmaları hakkında bize hiçbir şey söylemez. Acaba karşılaştırma sayısına gelince bir randomize algoritma log(n!) alt sınırını aşabilir mi? Cevap, yine hayır. Yine, bunu kanıtlamanın yolu randomize algoritmaların ne olduğu hakkında farklı düşünmektir. Aşağıdaki tartışmada, varsayalım ki karar ağaçlarımızı "temizlemek için şu yol takip ediliyor: Bazı girdi, a, dizisi tarafından ulaşılamayan herhangi bir düğüm silinmiştir. Bu temizlik sonrasında ağaç tam olarak n! yaprağa sahip olur. n! yaprağı vardır çünkü aksi takdirde, bu, doğru sıralamaya götürmezdi. En fazla n! yaprağı vardır, çünkü olası her farklı n elemanın n! permütasyonu, kökten başlayarak karar ağacının yapraklarına götüren tam bir yol oluşturur. 239

240 İki girdi alan deterministik, R, randomize sıralama algoritması düşünebiliriz. Sıralanması gereken bir girdi dizisi, a, ve [0, 1] aralığında rasgele reel sayılardan oluşan uzun bir dizi b = b1, b2, b3,, bm. Rasgele sayılar algoritma için randomizasyon sağlıyor. Algoritma yazı tura atmak ya da rasgele bir seçim yapmak istediğinde, bunu b içinden bazı elemanı kullanarak yapar. Örneğin, hızlı-sıralamanın ilk pivot endeksini hesaplamak için algoritma [nb1] formülünü kullanabilir. Şimdi farkına varmalısınız ki, eğer b bazı özel dizilimi tarafından sabitlenebilirse, ardından ilişkilendirilmiş karşılaştırma, ağacına, algoritması,, sahip olan R deterministik bir sıralama, olur. Sonra, fark etmelisiniz ki {1,, n} aralığında bir rasgele permütasyon seçtiğimizde, o zaman bu, nin içinden rasgele bir, w, yaprağını seçmek ile eşdeğerdir. Alıştırma 11.13, k yapraklı herhangi bir ikili ağaçtan seçilen rasgele bir yaprağın beklenen derinliğinin en az log k olduğunun kanıtlanmasını soruyor. Bu nedenle, (deterministik) algoritma, tarafından yapılan karşılaştırmaların beklenen sayısı {1,, n} rasgele bir permütasyon içeren bir girdi dizisi verildiğinde en az log(n!) olur. Son olarak, nin her seçimi için bu doğrudur, bu nedenle R için de geçerlidir. Bu randomize algoritmalar için alt sınır kanıtını tamamlar. Teorem Herhangi bir tam sayı n 1 için ve herhangi bir (deterministik veya randomize) karşılaştırmaya-dayalı sıralama algoritması, A, tarafından {1,, n} aralığında rasgele permütasyon sıralaması yaparken gerçekleştirilen karşılaştırmaların beklenen sayısı en az log(n!) = n log n O(n) olur Sayma Sıralama ve Taban Sıralaması Bu bölümde karşılaştırmaya dayalı olmayan iki sıralama algoritmasını çalışacağız. Küçük tamsayıları sıralamak için özelleştirilmiş olan bu algoritmalar, a elemanlarının (bir bölümünü) bir dizinin endeksleri gibi kullanarak, Teorem 11.5 in alt sınırlarını aşarlar. 240

241 şeklinde bir ifade düşünün. Bu ifade sabit zamanda çalışır, ancak, a[i] değerine bağlı olarak değişen c.length kadar farklı olası sonucu vardır. Bunun anlamı, bu tür bir komut içeren bir algoritmanın çalışması ikili ağaç olarak modellenemez. Sonuç olarak, bu bölümdeki algoritmaların karşılaştırmaya dayalı algoritmalardan daha hızlı sıralamalarını mümkün kılacak olan neden de budur Sayma Sıralaması Her biri 0,, k 1 aralığında n tamsayıdan oluşan bir girdi, a, dizisinin olduğunu varsayalım. Sayma-sıralama algoritması yardımcı bir c sayaç dizisi kullanarak, a yı sıralar. Yardımcı bir b dizisi olarak a nın sıralı versiyonunu çıktı olarak üretir. Sayma-sıralaması arkasındaki fikir basittir: Her i {0,, k 1} için, a içindeki i nin yinelenme sayısını sayın ve bunu c[i] de saklayın. Şimdi sıralama sonrasında, 0 ın yinelenme sayısını c[0], 1 in yinelenme sayısını c[1], 2 nin yinelenme sayısını c[2],, k 1 in yinelenme sayısını c[k 1] tutacaktır. Bu yapan kod çok alımlıdır, ve çalıştırması Şekil 11.7 'de gösterilmiştir: 241

242 Bu koddaki ilk for döngüsü her c[i] sayacını, a içindeki i yinelemelerini sayarak, ayarlar. a değerlerini endeks olarak kullanarak, bu sayaçların tümü O(n) zamanda tek bir for döngüsü içinde hesaplanabilir. Bu noktada, çıkış dizisi b yi doldurmak için doğrudan c yi kullanabiliriz. Ancak, a elemanlarının ilişkili verileri varsa, bu işe yaramaz. Bu nedenle b içine a elemanlarını kopyalamak için biraz fazladan çaba harcamak gerekir. O(k) zaman alan bir sonraki for döngüsü sayaçların toplamını hesaplar, böylece i'den daha az ya da eşit olan elemanların sayısı c[i] de saklanır. Özellikle, her i {0,, k 1} için, çıktı dizisi b nin değerleri olur. Son olarak, algoritma, kendi elemanlarını çıktı b dizisine sıralı olarak yerleştirmek için bir geri tarama başlatır. Tararken, a[i] = j elemanı b[c[j] 1] yerine yerleştirilir ve c[j] değeri 1 azaltılır. 242

243 Teorem countingsort(a, k) yöntemi {0,, k 1} kümesinden n tamsayıyı içeren a dizisini O(n+k) zamanda sıralayabilir. Sayma-sıralaması algoritmasının istikrarlı olmak gibi güzel bir özelliği vardır; eşit elemanların göreli sırasını korur. İki eleman a[i] ve a[j], aynı değere sahip olursa, ve i < j, o zaman b içinde a[i], a[j] den önce görünecektir. Bunun, bir sonraki bölümde anlatıldığı üzere yararları vardır Taban-Sıralaması Bir tamsayı dizisini sıralayan sayma-sıralaması, dizinin uzunluğu, n, dizideki görünür maksimum değerden, k 1, çok daha küçük olmadığı zaman çok verimlidir. Şimdi açıklayacağımız taban-sıralaması algoritması, çok daha büyük bir maksimum değer aralığını sağlamak için sayma-sıralamasının birkaç geçişini kullanıyor. Taban-sıralaması w-bit tamsayıları, her geçişte d bit olmak üzere, sıralamak için w/d geçişte sayma sıralamasını kullanır.20 Daha açık olarak, taban-sıralamasında tamsayılar önce en az önemli d bitine göre, daha sonra bir sonraki önemli d bitine göre, ve bu şekilde son seferde en önemli d bitine göre sıralanır. 20 d nin w yi böldüğünü varsayıyoruz. Aksi takdirde w, her zaman d w/d olarak artırılabilir. 243

244 (Bu kodda, (a[i]>>d * p)&((1<<d) 1) ifadesi ikili gösterimi a[i] nin (p + 1)d 1,,pd biti tarafından verilen tamsayıyı ayıklar.) Bu algoritmanın adımlarının bir örneği Şekil 11.8 'de gösterilmiştir. Bu olağanüstü algoritma doğru sıralar, çünkü sayma-sıralaması istikrarlı bir sıralama algoritmasıdır. a nın iki elemanı x < y ise ve x in, y den farklı olduğu bilinen en önemli biti r endeksine sahipse, o zaman r/d geçişi sırasında x, y nin önüne yerleştirilecektir ve daha sonraki geçişlerde x ve y nin göreli sırası değişmeyecektir. Taban-sıralaması w/d geçişten oluşan sayma-sıralaması çalıştırır. Her geçiş O(n+2d) çalışma zamanı gerektirir. Böylece, taban-sıralamasının performansı aşağıdaki teorem tarafından verilmiştir. Teorem Herhangi bir tamsayı d > 0 için, radixsort(a, k) yöntemi n adet w-bit tamsayı içeren bir a dizisini O((w/d)(n+2d)) çalışma zamanında sıralayabilir. Bunun yerine, dizinin elemanlarını {0, nc 1} aralığında düşündüğümüzde ve d = log n aldığımızda Teorem 11.8 in aşağıdaki sürümünü elde ederiz. Sonuç radixsort(a, k) yöntemi {0, nc 1} aralığından n tamsayı içeren bir, a, dizisini O(cn) çalışma zamanında sıralayabilir. 244

245 11.3. Tartışma ve Alıştırmalar Sıralama bilgisayar biliminin temel algoritmik bir problemidir, ve uzun bir geçmişi vardır. Knuth [48] birleştirerek-sıralama algoritması için von Neumann a (1945) atıfta bulunuyor. Hızlı-sıralamanın kaynağı Hoare [39] dır. Orijinal yığın-sıralama algoritması Williams [78] tarafından verilmiştir, ancak burada yer alan versiyonun (yığın aşağıdan-yukarıya O(n) zaman içinde oluşturuluyor) kaynağı Floyd [28] dur. Karşılaştırmaya dayalı sıralama için alt sınır folklor gibi görünür. Aşağıdaki tabloda, karşılaştırmaya dayalı algoritmaların performansları özetleniyor: karşılaştırmalar Birleştirerek-sıralama n log n Hızlı-sıralama 1,38n log n + O(n) Yığın-sıralama en-kötü 2n log n + O(n) beklenen en-kötü yerinde Hayır Evet Evet Bu karşılaştırmaya dayalı algoritmaların her birinin kendi avantajı ve dezavantajı vardır. Birleştirerek-sıralama en az karşılaştırma yapar ve randomizasyona dayanmaz. Ne yazık ki, birleştirme aşamasında bir yardımcı dizi kullanır. Bu diziyi tahsis etmek pahalı olabilir ve bellek sınırlı ise potansiyel bir başarısızlık noktasıdır. Hızlı-sıralama yerinde-işlem yapan bir algoritmadır ve karşılaştırmaların sayısı açısından en yakın ikincidir, ancak randomizedir, bu nedenle bu çalışma zamanı her zaman garanti edilmez. Yığın-sıralama en fazla karşılaştırma yapar, ama yerinde-işlem yapar ve deterministiktir. Birleştirme-sıralamasının net olarak en-önde olduğu bir durum vardır; bağlantılı-listeyi sıralarken bu gerçekleşir. Bu durumda, yardımcı dizi gerekli değildir; sıralı iki bağlantılı-liste işaretçi işlemeleri ile çok kolayca tek bir bağlantılı liste halinde birleştirilebilir (bkz. Alıştırma 11.2). Burada anlatılan sayma-sıralaması ve taban-sıralama algoritmaları Seward tarafından verilmiştir [68, Bölüm 2.4.6]. Ancak, taban-sıralamasının değişik çeşitleri, delikli kart sıralama makinelerini kullanan delikli kartları sıralamak için 1920'lerden beri kullanılmaktadır. Bu makineler kartın belirli bir yerindeki bir deliğin varlığına (ya da 245

246 yokluğuna) dayalı olarak kart destesini iki yığın halinde sıralayabilirler. Farklı delik yerleri için bu işlemi tekrar etmek taban-sıralamasının bir uygulamasını verir. Son olarak, sayma-sıralama ve taban-sıralamanın negatif olmayan tamsayıların yanı sıra diğer sayı türlerini de sıralamak için kullanılabilir olduğunu not ediyoruz. Basit değişiklikler yaparak sayma sıralama {a,, b} aralığındaki tamsayıları O(n+ b a) çalışma zamanında sıralayabilir. Benzer şekilde, taban-sıralama aynı aralıkta tamsayıları O(n (logn(b a) ) çalışma zamanında sıralayabilir. Son olarak, bu algoritmaların her ikisi de IEEE 754 kayan nokta formatında kayan nokta sayıları sıralamak için kullanılabilir. Bunun nedeni IEEE formatının, iki kayan noktalı sayıyı sanki işaretli-mutlak değer ikili gösteriminde birer tamsayıymış gibi karşılaştırması için tasarlanmış olmasıdır. Alıştırma ,7,4,6,2,8,3,5 içeren bir girdi dizisi için birleştirme-sıralama ve yığınsıralamanın çalışmasını gösterin. Aynı dizide hızlı-sıralamanın örnek bir olası çalışmasını verin. Alıştırma Birleştirme-sıralama algoritmasının yardımcı bir dizi kullanmadan Çifte Bağlantılı Liste yi sıralayan bir versiyonunu uygulayın. (bkz. Alıştırma 3.13.) Alıştırma Bazı quicksort(a, i, n, c) uygulamaları her zaman pivot olarak a[i] kullanır. Öyle bir girdi dizisi örneği verin ki, n uzunluğundaki bu dizi için uygulama karşılaştırma gerçekleştirsin. Alıştırma Bazı quicksort(a, i, n, c) uygulamaları her zaman pivot olarak a[i + n/2] kullanır. Öyle bir girdi dizisi örneği verin ki, n uzunluğundaki bu dizi için uygulama karşılaştırma gerçekleştirsin. Alıştırma Önce a[i],, a[i + n 1] değerlerine bakmaksızın pivotu deterministik olarak seçen herhangi bir quicksort(a, i, n, c) uygulamasının karşılaştırma gerçekleştirmesine neden olan n uzunluğunda bir girdi dizisinin her zaman var olduğunu gösterin. 246

247 Alıştırma karşılaştırma gerçekleştiren quicksort(a, i, n, c) uygulamasına bir argüman olarak geçirilen bir Karşılaştırıcı,c, tasarlayın. (İpucu: Karşılaştırıcının karşılaştırılan değerlere gerçekten bakması gerekli değerlidir.) Alıştırma Hızlı sıralama tarafından yapılan karşılaştırmaların beklenen sayısını Teorem 11.3 ün kanıtından biraz daha dikkatli olarak analiz edin. Özellikle, karşılaştırmaların beklenen sayısının 2n Hn n + Hn olduğunu gösterin. Alıştırma Yığın-sıralamanın en az 2n log n O(n) karşılaştırma gerçekleştirmesine neden olan bir girdi dizisi tanımlayın. Cevabınızı doğrulayın. Alıştırma Burada anlatılan yığın-sıralama uygulaması elemanlarını ters sırada sıralıyor ve daha sonra diziyi tersine çeviriyor. Bu son adım, girdi Karşılaştırıcı sının, c, sonucunu olumsuzlayan yeni bir Karşılaştırıcı tanımlayarak önlenebilir. Bunun neden iyi bir optimizasyon olmadığını açıklayın. (İpucu: Bir diziyi tersine çevirmenin ne kadar zaman aldığı ile ilgili olarak, yapılması gereken kaç olumsuzlama gerçekleştirilmesi gerektiğini düşünün.) Alıştırma Şekil 11.6 deki karşılaştırma ağacı tarafından doğru sıralanmayan başka bir çift 1, 2, 3 permütasyonu bulun. Alıştırma log n! = n log n O(n) olduğunu kanıtlayın. Alıştırma k yapraklı ikili ağacın yüksekliğinin en az log k olduğunu kanıtlayın. Alıştırma k yapraklı ikili ağaçtan rasgele bir yaprak almak istersek, o zaman bu yaprağın beklenen yüksekliğinin en az log k olduğunu kanıtlayın. Alıştırma Burada verilen radixsort(a, k) uygulaması girdi, a, dizisi, sadece negatif olmayan tamsayıları içerdiği zaman çalışıyor. Hem negatif ve hem de negatif olmayan tamsayıları içerdiğinde de düzgün çalışacak şekilde, bu uygulamayı genişletin. 247

248 Bölüm 12 Grafikler Bu bölümde, grafiklerin iki gösterimi ve bu gösterimleri kullanan temel algoritmalar inceleniyor. Matematiksel olarak, (yönlü) grafik bir G = (V, E) çiftinden oluşur. Burada, köşelerden oluşan bir küme V, kenar denilen sıralı köşe çiftlerinden oluşan bir küme E tarafından belirtilmektedir. (i, j) ile belirtilen bir kenarın yönü i köşesinden j köşesine doğrudur. i kenarın kaynağı olarak adlandırılır ve j hedef olarak adlandırılır. v0,, vk köşelerinden oluşan bir dizi ile G grafiğinde bir yol olarak belirtilir, öyle ki her i {1,, k} için (vi-1, vi) kenarı E kümesinin elemanıdır. eğer buna ek olarak, (vk, v0) kenarı da E nin içindeyse v0,, vk yolu bir döngüdür. Eğer tüm köşeleri benzersiz veya tekil ise, yol (veya döngü) basittir. Herhangi bir vi köşesinden herhangi bir vj köşesine bir yol varsa, vj nin vi dan ulaşılabilir olduğunu söyleyebiliriz. Bir grafik örneği Şekil 12.1 de gösterilmektedir. Birçok fenomeni modelleme yetenekleri nedeniyle, grafiklerin büyük sayıda uygulamaları vardır. Çok açık örnekler vardır. Bilgisayar ağları grafik olarak modellenebilir, köşeler bilgisayarlara karşılık gelirken bu bilgisayarlar arasındaki (yönlü) iletişim bağlantılarına kenarlar karşılık gelir. Şehir sokakları grafik olarak modellenebilir, köşeler kavşaklar temsil edilirken, ardışık kavşakları birleştiren sokaklar kenarlar tarafından gösterilir. Daha az belirgin örnekler grafiklerin bir küme içindeki ikili ilişkileri modelleyebildiğini fark ettiğimizde ortaya çıkar. Örneğin bir üniversite ortamında, bir ders programı çatışma grafiği oluşturulabilir, burada köşeler üniversitede sunulan dersleri temsil ederken, hem sınıf i ve hem de sınıf j yi alan en az bir öğrenci varsa, (i, j) kenarı dahil edilmektedir. Böylece, bir kenarın söylediği, i sınıfı için bir sınav düzenlenecekse aynı saatte j sınıfı için bir sınavın düzenlenmemesi gerektiğidir. 248

249 Bu bölüm boyunca, G köşe sayısını göstermek için n ve G kenarlarının sayısını göstermek için m kullanacağız. Yani, n = V ve m = E. Ayrıca varsayacağız ki, V = {0,, n 1}. V elemanları ile ilişkilendirmek istediğimiz diğer başka veriler n uzunluğunda bir dizide depolanabilir. Grafikler üzerinde yapılan bazı tipik işlemler şunlardır: addedge(i, j) removeedge(i, j) : E içindeki (i, j) hasedge(i, j) : (i, j) E, outedges(i) : (i, j) E olan inedges(i) : (j, i) E olan : E için bir (i, j) kenarı ekler. kenarını siler. kenar olduğunu kontrol eder. tüm j tamsayılarının bir Liste sini döndürür. tüm j tamsayılarının bir Liste sini döndürür. Bu işlemleri verimli uygulamanın çok da zor olmadığını unutmayın. Örneğin, ilk üç işlem Sırasız Küme kullanılarak doğrudan uygulanabilir, bu nedenle Bölüm 5 te ele alınan karma 249

250 tabloları kullanarak sabit beklenen zamanda uygulanabilir. Son iki işlem, her bir köşe için, bitişik köşelerin bir listesini depolayarak sabit zamanda uygulanabilir. Ancak, farklı grafik uygulamaları için bu işlemlerin farklı performans gereksinimleri vardır, ve, ideal olarak, uygulamanın tüm gereksinimlerini karşılayan en basit uygulamayı kullanmalıyız. Bu nedenle, grafik gösterimlerini iki geniş kategoride tartışacağız Bitişiklik Matrisi: Bir Grafiğin Matris ile Gösterimi Bitişiklik matrisi n köşeli bir G = (V, E) grafiğini elemanları boolean değerler olan n x n matris ile göstermenin bir yoludur. Matris elemanları a[i][j] olarak tanımlanmaktadır. Şekil 12.1 deki grafik için bitişiklik matrisi, Şekil 12.2 de gösterilmiştir. Bu gösterimde, addedge(i,j), removeedge(i,j), ve hasedge(i, j) işlemleri sadece a[i][j] elemanını belirlemeyi veya okumayı içerir: 250

251 Açıktır ki, bu işlemler işlem başına sabit zaman alır. 251

252 Bitişiklik matrisinin kötü bir performans sergilediği işlemler outedges(i) ve inedges(i) olmuştur. Bunları uygulamak için, a nın karşılık gelen satır veya sütunundaki bütün n elemanlarını taramamız ve sırasıyla a[i][j] ve a[j][i] nin true değer olduğu tüm j endekslerini toplamamız gerekmektedir. Açıktır ki, bu işlemler işlem başına O(n) çalışma zamanı alır. Bitişiklik matrisi ile gösterimin diğer bir dezavantajı da büyük olmasıdır. n x n boolean matrisini depolar, bu nedenle en az n2 bit bellek gerektirir. Buradaki uygulama boolean değerlerden oluşan bir matris kullanıyor, bu nedenle, gerçekten n2 bayt büyüklüğünde belleğe ihtiyaç duyuluyor. Her bellek sözcüğünün içine w boolean değerleri paketleyen daha dikkatli bir uygulama, alanı kullanımını O(n2/w) bellek sözcüğüne kadar azaltabilir. Teorem Bitişiklik Matrisi veri yapısı Grafik arayüzünü uygular. Bitişiklik Matrisi aşağıdaki işlemleri destekler: İşlem başına sabit zamanda çalışan addedge(i, j), removeedge(i, j), ve hasedge(i, j); ve İşlem başına O(n) zamanda çalışan inedges(i), ve outedges(i). Bitişiklik Matrisi tarafından kullanılan alan O(n2) dir. 252

253 Yüksek bellek gereksinimlerine ve inedges(i) ve outedges(i) işlemlerinin kötü performansına rağmen, Bitişiklik Matrisi hala bazı uygulamalarda kullanışlı olabilir. Özellikle, grafik G yoğunsa, yani kenar sayısı n2 ye yakınsa, o zaman n2 bellek kullanımı kabul edilebilir. Bitişiklik Matrisi veri yapısı aynı zamanda yaygın olarak kullanılır, çünkü a matrisi üzerindeki cebirsel işlemler G grafiğinin özelliklerini etkili bir şekilde hesaplamak için kullanılabilir. Bu algoritmalar dersi için bir konudur, ama biz burada şöyle bir özelliği işaret edeceğiz: a nın girdilerini tamsayı olarak kabul edersek (true için 1 ve false için 0) ve matris çarpımı kullanarak a nın kendisi ile çarpmasını alırsak o zaman matris a2 yi elde ederiz. Matris çarpımı tanımından hatırlayın ki, bu Bu toplamı G grafiği açısından yorumlarsak, G hem (i, k) ve hem (k, j) kenarlarını içerirken bu formül köşe sayısını, k, sayar. Yani, ara köşeler, k, üzerinden uzunluğu tam olarak iki olan i'den j ye yolları sayar. Bu gözlem,, sadece O(log n) matris çarpımı kullanarak G nin bütün köşe çiftleri arasındaki en kısa yolları hesaplayan bir algoritmanın temelini oluşturur Bitişiklik Listeleri: Liste Derlemi olarak Grafik Bitişiklik listeleri ile grafik gösterimi daha köşe-merkezli bir yaklaşım gerektirir. Bitişiklik listelerinin birçok olası uygulamaları vardır. Bu bölümde, basit bir tanesini sunuyoruz. Bölümün sonunda, farklı olasılıkları ortaya koyacağız. Bitişiklik listeleri gösteriminde G = (V, E) grafiği bir liste dizisi, adj, olarak temsil edilir. adj[i] listesi i köşesine bitişik tüm köşelerin bir listesini içerir. Yani, (i, j) E olan her j endeksini içerir. (Bir örnek Şekil 12.3 de gösterilmiştir.) Bu özel uygulamada, adj içindeki her liste bir Dizi Yığıt olarak temsil edilmiştir, çünkü konuma göre erişim için sabit zaman gereksinimini 253

254 sağlamak istiyoruz. Diğer seçenekler de mümkündür. Özellikle, adj bir Çifte Bağlantılı Liste olarak da gerçekleştirilebilirdi. addedge(i, j) işlemi sadece j değerini adj[i] listesine ekler: Bu sabit zaman alır. 254

255 removeedge(i, j) işlemi j değerini adj[i] listesinde bulana kadar arar, ve bulduğunda siler: Bu, O(der(i)) zaman alır, burada der(i), (i derecesi) kaynağı i olan E kenarlarının sayısını sayar. hasedge(i, j) işlemi de benzerdir; j değerini adj[i] listesinde bulana kadar arar (ve true döndürür), veya listenin sonuna ulaşır (ve false döndürür): Bu da O(der(i)) zaman alır. outedges(i) işlemi çok basittir; adj[i] listesini döndürür: Bu açık bir şekilde, sabit bir zaman alır. inedges(i) işlemi daha çok çalışma gerektirir. Her j köşesinin üzerinden tarayarak (i, j) kenarının bulunup bulunmadığı kontrol edilir, ve eğer bulunuyorsa, çıktı listesine j eklenir: 255

256 Bu işlem çok yavaştır. Her köşenin bitişiklik listesini tarar, bu nedenle O(n + m) zaman alır. Aşağıdaki teorem yukarıdaki veri yapısının performansını özetler: Teorem Bitişiklik Listeleri veri yapısı Grafik arayüzünü uygular. Bitişiklik Listeleri aşağıdaki işlemleri destekler: İşlem başına sabit zamanda çalışan addedge(i, j); İşlem başına O(der(i)) zamanda çalışan removeedge(i, j) ve hasedge(i, j); İşlem başına sabit zamanda çalışan outedges(i); ve İşlem başına O(n + m) zamanda çalışan inedges(i). Bitişiklik Listeleri tarafından kullanılan alan O(n + m) olur. Daha önce değinildiği gibi, bir grafiği bitişiklik listesi olarak uygularken yapılacak pek çok farklı seçenek vardır. Aklımıza gelen bazı sorular şunlardır: Her adj elemanını saklamak için ne tür bir derlem kullanılmalıdır? Bir dizi-tabanlı liste, bir bağlantılı liste, hatta bir karma tablosu kullanılabilir. Her i köşesi için (j, i) E olan j köşe listesini saklayan ikinci bir bitişiklik listesi, inadj, olmalı mıdır? Böylece, inedges(i) çalışma zamanını büyük ölçüde azaltılabilir, ancak kenarları eklerken veya silerken biraz daha fazla çalışma gerektirir. adj[i] içindeki (i, j) kenar girdisi kendisine inadj[j] içinde karşılık gelen girdiye bir referans vererek bağlanmalı mıdır? 256

257 Kenarlar kendi ilişkili verileri ile birinci sınıf nesneler olmalı mıdır? Bu şekilde, adj köşeler (tamsayılar) listesinden ziyade kenarların listelerini içerecektir. Bu soruların çoğu uygulamanın karmaşıklığı (ve gerektirdiği alan) ile performans özelliklerinden birini elde ederken diğerinden vazgeçmeyi beraberinde getirir Grafik Ziyaretleri Bu bölümde bir grafiği keşfetmek için grafiğin, i, köşesinden başlayarak, i den ulaşılabilir bütün köşelerini bulan iki algoritma sunuyoruz. Bu algoritmaların ikisi de bitişiklik listesi gösterimini kullanarak temsil edilen grafikler için uygundur. Bu nedenle, bu algoritmalar analiz edilirken temel gösterimin Bitişiklik Listeleri olduğunu kabul edeceğiz Enine-Arama Enine-arama algoritması, i, köşesinden başlar ve ilk olarak, i nin komşularını ziyaret eder, sonra i nin komşularının komşularını ziyaret eder, sonra i nin komşularının komşularının komşularını ziyaret eder, ve benzeri. Bu algoritma ikili ağaçlar için enine-arama algoritmasının (Bölüm 6.1.2) bir genellemesi ve çok benzeridir; başlangıçta sadece i yi içeren bir kuyruk, q, kullanır. Daha sonra tekrar tekrar q nin bir elemanını alır ve bu elemanın komşularının daha önce q içinde olmaması şartıyla, komşularını q ya ekler. Grafikler ve ağaçlar için enine-arama algoritması arasındaki tek büyük fark, grafikler için tasarlanan algoritmanın birden fazla aynı kez q köşe noktasını eklememesidir. Bunu sağlarken, hangi köşelerin zaten keşfedilmiş olduğunu tutan yardımcı bir boolean dizi, seen, kullanır. 257

258 Şekil 12.1 deki grafik üzerinde bfs(g, 0) çalıştırılmasının bir örneği Şekil 12.4 de gösterilmiştir. Bitişiklik listelerinin sıralanmasına bağlı olarak farklı çalıştırmalar mümkündür. Şekil 12.4, Şekil 12.3 teki bitişiklik listelerini kullanmaktadır. bfs(g, i) rutininin çalışma zamanını analiz etmek oldukça basittir. seen dizisinin kullanılmasıyla, q köşelerinin hiçbiri birden fazla eklenmez. Her q köşesini eklemek (ve daha sonra silmek) köşe başına sabit zaman alır, toplamda bu O(n) zaman eder. Her bir köşe en fazla bir kere iç döngü tarafından işlendiği için, her bitişiklik listesi, en fazla bir kez işlenir, 258

259 yani G nin her bir kenarı en fazla bir kere işlenir. İç döngü içinde yapılan bu işlem, yineleme başına sabit zaman alır ve toplamda O(m) zaman eder. Bu nedenle, algoritmanın tamamı O(n+m) zamanda çalışır. Aşağıdaki teorem bfs(g, r) algoritmasının performansını özetlemektedir. Teorem Bitişiklik Listeleri veri yapısı kullanılarak uygulanan bir girdi Grafik, g, verildiğinde bfs(g, r) algoritması O(n+m) zamanda çalışır. Bir enine-aramanın çok özel bazı özellikleri vardır. bfs(g, r) çağrısı en sonunda her j köşesini r den j ye yönlü bir yol olacak şekilde kuyruğa ekler (ve en sonunda kuyruktan çıkarır). Ayrıca, r ye 0 mesafesindeki köşeler (r nin kendisi) 1 mesafesindeki köşelerden önce q içine girecektir. 1 mesafesindeki köşeler, 2 mesafesindeki köşelerden önce q içine girecektir, ve benzeri. Bu nedenle, bfs(g, r) yöntemi r ye olan mesafesi artan sırada olacak şekilde köşeleri ziyaret eder, ve r tarafından ulaşılamayan köşeler asla hiç ziyaret edilmez. Enine-arama algoritmasının özellikle yararlı bir uygulaması, bu nedenle, en kısa yolları hesaplamaktır. Her köşe için, r den en kısa yolu hesaplamak için, n uzunluğunda bir yardımcı p dizisi kullanan değişik bir bfs(g, r) kullanıyoruz. Yeni köşe j, q ya eklendiğinde, p[j] = i olarak belirlenir. Bu şekilde, p[j], r den j ye en kısa yol üzerindeki ikinci son düğüm olur. Bunun tekrarlanmasıyla, p[p[j], p[p[p[j]]], ve benzerini alarak, r den j ye en kısa bir yolu (ters yönde) yeniden oluşturabiliriz İlkin-Derinliğine Arama İlkin-derinliğine-arama algoritması ikili ağaçları ziyaret etmek için tasarlanan standart algoritmaya benzer; geçerli düğüme dönmeden önce ilk bir altağacı tamamen araştırır, ve daha sonra diğer altağacı araştırır. İlkin-derinliğine-aramayı düşünmek için başka bir yol enine-aramanın bir nokta dışında benzeridir, kuyruk yerine yığıt kullanır. İlkin-derinliğine-arama algoritmasının çalışması sırasında, her i köşesine, bir renk, c[i] atanır: daha önce köşeyi görmemişsek white (beyaz), şu anda bu köşeyi ziyaret ediyorsak gray (gri), 259

260 ve bu köşeyi ziyaret ettiysek black (siyah). İlkin-derinliğine-aramayı düşünmenin en kolay yolu onu bir özyinelemeli algoritma olarak düşünmektir. r köşesini ziyaret ederek başlarız. i köşesini ziyaret ederken, ilk olarak i gri olarak işaretlenir. Sonra, i'nin bitişiklik listesini tararız ve özyinelemeli olarak bu listede bulabildiğimiz herhangi bir beyaz köşeyi ziyaret ederiz. Son olarak, i işlenmesi tamamlandığında, i siyah renkle işaretlenir ve dönüş yapılır. Bu algoritmanın çalıştırmasının bir örneği Şekil 12.5 de gösterilmiştir. 260

261 İlkin-derinliğine-arama iyi bir özyinelemeli algoritma olarak düşünülebilir olsa da, özyineleme bunu uygulamak için en iyi yol değildir. Nitekim, yukarıda verilen kod birçok büyük grafik için yığıt taşmasına yol açarak başarısız olur. Alternatif bir uygulama özyineleme yığıtını, açık bir yığıt ile, s, ile değiştirmektir. Aşağıdaki uygulama tam olarak bunu yapar: Yukarıdaki kodda, bir sonraki köşe, i, işlendiğinde, i gri renge boyanır ve sonra, yığıt üzerinde, bitişik köşeler ile yer değiştirir. Sonraki yineleme sırasında, bu köşelerden biri ziyaret edilecektir. Beklendiği gibi, dfs(g, r) ve dfs2(g, r) çalışma zamanları bfs(g, r) ile aynıdır: Teorem Bitişiklik Listeleri veri yapısı kullanılarak uygulanan bir girdi Grafik, g, verildiğinde dfs(g, r) ve dfs2(g, r) algoritmalarının her biri O(n+m) zamanda çalışır. Enine-arama algoritmasında olduğu gibi, ilkin-derinliğine-aramanın her çalıştırması ile ilişkili altta yatan bir ağaç vardır. i r olan bir düğüm beyazdan griye doğru gittiğinde bunun nedeni dfs(g, i, c) bir i düğümünü işlerken özyinelemeli olarak çağrılmıştır. (dfs2(g, r) algoritmasında, i yığıtta i yerini alan düğümlerden biridir.) Eğer i menşei olarak i düşünülürse, o zaman r köklü bir ağaç elde edilir. Şekil 12.5 te bu ağaç köşe 0 dan köşe 11 için bir yoldur. İlkin-derinliğine-aramanın önemli bir özelliği şudur: Varsayalım ki, düğüm i gri renkli olduğunda, i den diğer bazı j düğümü için sadece beyaz köşeleri kullanan bir yol vardır. O 261

262 zaman j ilk olarak gri renkli olacak, sonra i siyah olmadan önce siyah renkli olacaktır. (Bu, i den j ye herhangi bir, P, yolunu dikkate alarak çelişki yöntemi ile kanıtlanabilir.) Bu özelliğin bir uygulaması döngülerin saptanmasıdır. Şekil 12.6 ya bakın. r dan ulaşılabilir bir, C, döngüsünü düşünün. i, C'nin ilk gri renkli düğümü olsun, ve C döngüsü üzerinde i öncesindeki düğüm j olsun. Daha sonra, yukarıda belirtilen özellik ile, j gri renkli olacak ve i hala gri iken (j, i) kenarı algoritma tarafından kabul edilecektir. Bu nedenle, algoritma ilkinderinliğine-arama ağacında i den j ye bir yol, P, olduğu ve (j, i) kenarının bulunduğu sonucuna varabilir. Bu nedenle, P, aynı zamanda bir döngüdür Tartışma ve Alıştırmalar İlkin-derinliğine-arama ve enine-arama algoritmalarının çalışma zamanları Teorem 12.3 ve 12.4 tarafından biraz abartılmıştır. nr, r dan i için yolu var olan G nin i köşelerinin sayısını belirtsin. mr bu köşeleri kaynak olarak alan kenarların sayısını belirtsin. O zaman, aşağıdaki teorem enine-arama ve ilkin-derinliğine-arama algoritmalarının çalışma sürelerini veren daha kesin bir ifadedir. (Çalışma zamanlarının bu daha rafine ifadesi alıştırmalarda özetlenen bu algoritmaların bazı uygulamalarında faydalıdır.) Teorem Bitişiklik Listeleri veri yapısı kullanılarak uygulanan bir girdi Grafik, g, verildiğinde bfs(g, r), dfs(g, r) ve dfs2(g, r) algoritmalarının her biri O(nr+mr) zamanda çalışır. 262

263 Enine-arama Moore [52] ve Lee [49] tarafından sırasıyla labirent keşif ve devre yönlendirme gibi bağlamlarda bağımsız olarak keşfedilmiştir. Grafiklerin Bitişiklik Listesi gösterimleri Hopcroft ve Tarjan [40] tarafından (o zaman daha yaygın olan) Bitişiklik Matrisi gösterimi için bir alternatif olarak sunuldu. Bu temsil, ilkinderinliğine-arama ile birlikte, kenarlarının herhangi bir çifti birbirine çapraz olmayan bir grafiğin [41] O(n) zamanda bir düzlemde çizilip çizilemeyeceğini belirleyen, ünlü HopcroftTarjan düzlemsellik test algoritmasında önemli bir rol oynadı. Aşağıdaki alıştırmalarda, yönsüz grafik, her i ve j için (i, j) kenarının ancak ve ancak (j, i) kenarı mevcutsa mevcut olan bir grafiktir. Alıştırma Şekil 12.7 deki grafiğin Bitişikliklik Listesi gösterimini ve Bitişiklik Matrisi gösterimini çizin. Alıştırma G grafiğinin geliş matrisi gösterimi n x m matrisi, A, olarak aşağıdaki gibi tanımlanır. 263

264 1. Şekil 12.7 deki grafiğin geliş matrisi gösterimini çizin. 2. Bir grafiğin geliş matrisi gösterimini tasarlayın, analiz edin ve uygulayın. addedge(i, j), removeedge(i, j), hasedge(i, j), inedges(i), ve outedges(i) çalışma zamanları ve alan gereksinimini analiz etmeniz gerekiyor. Alıştırma Şekil 12.7 deki, G, grafiği üzerinde bfs(g, 0) and dfs(g, 0) çalıştırmasını gösterin. Alıştırma G yönsüz bir grafik olsun. G grafiğinin her i, j köşe çifti için i den j ye bir yol varsa (G yönsüz grafik olduğu için j den i ye de bir yol vardır) bağlanmış olduğu söylenir. O(n+m) zamanda G nin bağlanmış olduğunun nasıl test edileceğini gösterin. Alıştırma G yönsüz bir grafik olsun. G nin bağlanmış-bileşenli etiketlemesi G köşelerini büyükçe kümeler halinde bölümler. Bunların her biri, bağlanmış bir alt grafiği oluşturur. O(n+m) zamanda G nin bağlanmış-bileşenli etiketlemesinin nasıl hesaplanacağını gösterin. Alıştırma G yönsüz bir grafik olsun. G den yayılan orman ağaçları, bileşen başına kenarları G kenarları olan ve köşeleri G nin bütün köşelerini içeren ağaçların bir derlemidir. O(n+m) zamanda G nin yayılan ormanının nasıl hesaplanacağını gösterin. Alıştırma G grafiğinin her i, j köşe çifti için i den j ye bir yol varsa kuvvetli-bağlanmış olduğu söylenir. O(n+m) zamanda G nin kuvvetli-bağlanmış olduğunun nasıl test edileceğini gösterin. Alıştırma G = (V, E) grafiği ve bazı özel köşe r V için r dan i için her i V köşesi için en kısa yol uzunluğunun nasıl hesaplanacağını gösterin. Alıştırma dfs(g, r) kodunun bir grafiğin düğümlerini dfs2(g, r) den farklı olan bir sıra içinde ziyaret etmesine (basit) bir örnek verin. dfs(g, r) ile tam olarak aynı sırada düğümleri ziyaret eden dfs2(g, r) in bir versiyonunu yazın. (İpucu: r in kaynağı olduğu kenar sayısı 1 den fazla iken her iki algoritmanın herhangi bir grafik üzerinde çalışmasını izleyin.) 264

265 Alıştırma G grafiğinin evrensel çıkış düğümü n 1 kenarın hedefi olan, ancak hiçbir kenarı olmayan bir köşedir.21 Bitişiklik Matrisi ile gösterilen bir G grafiğinin evrensel çıkış düğümünün var olduğunu test eden bir algoritma tasarlayın ve uygulayın. 21 Evrensel çıkış düğümü, v, özel bir düğümdür: Herkes v yi odada tanıyor iken v odadaki kimseyi tanımıyor. 265

266 Bölüm 13 Tamsayılar için Veri Yapıları Bu bölüm Sıralı Küme veri yapısı ve uygulaması ile ilgilidir. Sıralı Küme de saklanan elemanlar w-bit tamsayılar olarak kabul edilmiştir. Yani, x {0, 2w 1} için ekle(x), sil(x), ve bul(x) işlemlerini uygulamak istiyoruz. Verinin ya da en azından veri sıralamak için kullandığımız anahtarın tamsayı olduğu pek çok uygulama olduğunu düşünmek zor olmasa gerekir. Önce gelen fikrin bir sonraki fikri oluşturduğu üç veri yapısını tartışacağız. İlk yapı, İkili Sıralı Ağaç her zaman Sıralı Küme işlemlerinin üçünü birden O(w) zamanda gerçekleştirir. Bu beklentimiz dahilindedir, çünkü {0,, 2w 1} içinden herhangi bir alt küme n 2 w boyutuna sahiptir, ve böylece log n w. Bu kitapta değinilen Sıralı Küme uygulamalarının hepsi O(log n) zamanda çalışır. Bu yüzden hepsi en azından bir İkili Sıralı Ağaç gibi hızlıdır. İkinci yapı X-Hızlı Sıralı Ağaç, karmayı kullanarak İkili Sıralı Ağaç içinde yapılan bir aramayı hızlandırır. Bu hızın arttırılması ile, bul(x) işlemi O(log w) zamanında çalışır. Ancak, X-Hızlı Sıralı Ağaç içindeki ekle(x) ve sil(x) işlemleri hala O(w) zaman alabilir ve X-Hızlı Sıralı Ağaç tarafından kullanılan alan O(n. w) olur. Üçüncü yapı, Y-Hızlı Sıralı Ağaç her w elemanı içinden X-Hızlı Sıralı Ağaç ı kullanarak sadece bir örnek depolar ve kalan elemanları standart bir Sıralı Küme yapısında saklar. Böylece ekle(x) ve sil(x) çalışma zamanı O(log w) ve alan gereksinimi O(n) olur. Bu bölümde örnek olarak kullanılan uygulamalar, tamsayı ile bağlantı edilebilen her türlü veriyi saklayabilir. Kod örneklerinde tamsayı olarak x değeri kullanılmıştır. x ile ilişkili tamsayı değeri, her zaman değişken ix ile gösteriliyor, ve in.intvalue(x) yöntemi x ile ilişkili tamsayı değerini döndürüyor. 266

267 13.1. İkili Sıralı Ağaç: Sayısal Arama Ağacı İkili Sıralı Ağaç, ikili ağaç içindeki w-bit tamsayıları şifreler. Ağaçtaki tüm yaprakları w derinliğindedir ve her tamsayı kökten-yaprağa bir yol olarak kodlanmıştır. i nci en anlamlı bit, 0 ise, x tamsayısı için yol i seviyesinde sola doğru gider. 1 ise sağa gider. Şekil 13.1 w = 4 durumu için tamsayılar 3 (0011), 9 (1001), 12 (1100), 13 (1101) depolandığı örnek bir ağaç gösteriyor. Herhangi bir x değeri için arama yolu x bitlerine bağlı olduğu içindir ki, bir düğümün çocuklarını u, u.child[0] (sol) ve u.child[1] (sağ) olarak isimlendirmek yararlı olacaktır. child olarak adlandırılan bu işaretçilerin birden çok fonksiyonu vardır. İkili Sıralı Ağaç ın yapraklarında çocuk yoktur. İşaretçilerin fonksiyonu yaprakları bir araya getirmektir. Bunun için bir Çifte-Bağlantılı Liste (ÇBListe) yaprakların sırasını kaydetmeye yarayabilir. İkili Sıralı Ağaç içindeki bir yaprak için, u.child[0] (prev) listede u öncesine referans verir. u.child[1] (next) listede u sonrasına referans verir. Özel bir düğüm, dummy, hem ilk düğümün öncesine, hem son düğümün sonrasına referans verir (Bkz. Bölüm 3.2). Her, u, düğümü ayrıca u.jump adında bir ek işaretçi içerir. u düğümü için solundaki çocuk mevcut değilse, u.jump, u altağacındaki en küçük yaprağa işaret eder. Sağındaki çocuk mevcut değilse, u.jump, u altağacındaki en büyük yaprağa işaret eder. jump işaretçilerini 267

268 gösteren bir İkili Sıralı Ağaç örneği ve yaprakları Çifte-Bağlantılı Liste halinde Şekil 13.2 de gösterilmiştir. İkili Sıralı Ağaç ın bul(x) yöntemi oldukça kolaydır. Arama yolunun başlangıcında u düğümleri arasından x yaprağı aranır. Eğer öyleyse, x bulunmuş olur. u düğümüne ulaşmaya devam edilemezse, (x çocuğu yoksa, yani yaprağa ulaşıldıysa), u.jump yolu aranır. Bu arama bizi x den büyük en küçük yaprağa, yada x den küçük en büyüğe götürür. Bu iki durumdan hangisinin önce oluşmasını, u düğümünün sol mu sağ mı çocuğunun, sırasıyla, eksik yada var olmasına bağlayabiliriz. Birinci durumda (u, sol çocuğu eksik), istediğimiz düğüm bulunmuş 268

269 olur. İkinci durumda (u, sağ çocuğu eksik), istediğimiz düğüme ulaşmak için bağlantılı liste yardımcı olacaktır. Bu durumların her biri, Şekil 13.3 te gösterilmiştir. bul(x) yönteminin çalışma zamanı kökten yaprağa aldığı yol cinsinden O (w) olur. İkili Sıralı Ağaç ın ekle(x) işlemi kolay, ancak oldukça zahmetlidir: 1. Arama yolu üzerinde u düğümü için ulaşılabilen son düğüme kadar arama yapılır. 2. u düğümünden başlayarak arama yolunun kalanı için, x içeren bir yaprağa kadar arama yolu kaydedilir. 269

270 3. x içeren bir u düğümü oluşturularak bağlantılı yaprak listesine eklenir (Birinci adımda en son ziyaret edilen, u, düğümüne ait olan jump işaretçisinin gösterdiği bağlantılı listenin içinden u öncesine, pred, erişim sağlanmalıdır.) 4. x arama yolu üzerindeki jump işaretçilerinin x referansını gösteren tüm değişiklikler yapılır. 270

271 Şekil 13.4 te örnek bir ekleme çalıştırılması gösteriliyor. Bu yöntemin çalıştırılması sırasında x için önce ileri, sonra geri yönde birer arama yolu bulunuyor. Her iki takip de sabit zamanda çalışır, bu nedenle ekle(x) yönteminin çalışma zamanı O(w) olur. sil(x) bir anlamda ekle(x) için yapılanları yok eder. Şu adımlar u düğümünü silmeye yarar: 1. u düğümü arama yolu üzerinden x içeren yaprağa ulaşana kadar aranmalıdır. 2. Çifte-bağlantılı listeden u silinmelidir. 3. u silindikten sonra x için arama yolu üzerinde olmayan bir çocuğa sahip v düğümü ulaşılana kadar arama yolu ardı sıra silinir. 4. u ya işaret veren her jump işaretçisini güncellemek için başlangıcı v sonu kök olan yeni bir yol oluşturulur. Şekil 13.5 te örnek bir silme çalıştırılması gösteriliyor. Teorem İkili Sıralı Ağaç w-bit tamsayılar için Sıralı Küme arayüzünü uygular. İkili Sıralı Ağaç işlem başına O(w) zamanda çalışan ekle(x), sil(x), ve bul(x) işlemlerini destekler. n değer içeren İkili Sıralı Ağaç ın kullanması gerekli alan O(n. w) kadardır. 271

272 13.2 X-Hızlı Sıralı Ağaç: Çifte-Logaritmik Zamanda Arama X-Hızlı Sıralı Ağaç ın yapısının performansı çok etkileyici değildir. Veri yapısında depolanan eleman sayısı, n, en çok 2W olarak kabul edilirse, log n w olur. Diğer bir deyişle, bu kitabın diğer bölümlerinde açıklanan karşılaştırmaya-dayalı Sıralı Küme yapılarının herhangi biri en az İkili Sıralı Ağaç kadar verimlidir, ve sadece tamsayı depolama ile sınırlı değildir. 272

273 Bu bölümde X-Hızlı Sıralı Ağaç yapısı tanıtılıyor. Bu yapıdaki sıralı ağacın her seviyesi birer w+1 karma tabloya sahiptir ve yapı İkili Sıralı Ağaç a çok benzerdir. Bu karma tablolar ile bul(x) işleminin O(log w) zamanda çalışması mümkündür. Hatırlayın ki, İkili Sıralı Ağaç ta bulunan x için bul(x) işlemi sırasında arama yolu u düğümü için u.right yada u.left tarafına yöneldiğinde, ancak u.right ve u.left çocukları yoksa arama neredeyse tamamlanıyordu. Bu noktada, arama u.jump yardımıyla bir yaprağa ağaç üzerinden atlama yapar ve ya v yada yaprakları depolayan bağlantılı-liste içinden v den sonra geleni döndürür. X-Hızlı Sıralı Ağaç u düğümünü bulmak için ağacın her düzeyinde ikili arama prosedürünü gerçekleştirerek arama işlemini hızlı hale getirir. Burada, aranan u düğümünün belirli seviyelerin üstünde mi yoksa altında mı veya neresinde sorusu için ikili arama gerçekleştiriliyor. x ikili gösteriminde en önemli i nci bit kökten i nci seviyeye çizilen arama yolunu belirlemede gereklidir. Şekil 13.6 a göre 14 sayı değerine (ikili gösterimi 1110) ait arama yolu üzerindeki son, u, düğümü 2.seviyede düğümdür, çünkü 3.seviyede ile etiketlenmiş ile etiketli herhangi bir düğüm yoktur. Böylece, i seviyesindeki her düğüm i-bitlik bir tamsayı tarafından etiketlenir. Aradığımız u düğümünün i seviyesinde veya altında mı olduğu ancak ve ancak i düzeyindeki etiketin x nin en önemli i-bitine karşılık gelmesi ile mümkün olur. 273

274 Her i {0,, w} seviyesi için X-Hızlı Arama Ağacı nda karma tabloyu uygulayan t[i] düğümlerinin hepsi Sırasız Küme nin içinde saklanır (Bölüm 5). Bu Sırasız Küme sayesinde i düzeyinde x in en önemli i-biti ile etiketlenmiş bir düğüm olduğunu kontrol etmek beklenen bir sabit zamanda gerçekleşir. Bunu düğüm t[i].bul(x >> (w i)) sonucuna göre de belirleyebiliriz. t[0] t[w] karma tabloları üzerinde yapılan ikili arama gerçekleştirimiyle u nun yeri belirlenir. Başlangıçta, u nun 0 < i < w+1 seviyesinde olduğu biliniyor. Bu nedenle çalıştırmaya l = 0 ve h = w + l ile başlanır ve i = b(l + h)=2c denklemini sağlayan t[i] karma tablosunda x in en önemli i-biti ile etiketlenmiş düğümün içerildiğini kontrol ederiz. Doğruysa, l = i belirlemesi yapılır (u, i seviyesinde veya altındadır.); aksi takdirde, h = i belirlemesi yapılır (u, i seviyesinin üstündedir). h l 1 koşulu bu işlemi sonlandırır; çünkü l seviyesinde u nun yeri belirlenmiştir. Daha sonra u.jump ile yapraklara ulaşılır, bağlantılı listede yapılan bir arama ile bul (x) işlemi tamamlanır. Yukarıdaki yöntemde while döngüsü içinde işlem gören her h 1 yinelemesi arama mesafesini yaklaşık olarak 2 faktör oranında azaltır. Bu nedenle döngünün O(log w) tekrarından sonra u beklenen sabit bir zamanda bulunur. Kalan çalışmalar sadece sabit zaman alır, böylece X-Hızlı Sıralı Ağaç ın bul(x) yöntemi O(log w) beklenen zamanda çalışır. 274

275 X-Hızlı Sıralı Ağaç ın ekle(x) t[0]. t[w] ve sil(x) yöntemleri İkili Sıralı Ağaç ile hemen hemen aynıdır. karma tabloları için sadece yönetimsel değişiklikler yapılması yeterlidir. ekle(x) işlemi sırasında yeni bir düğüm i seviyesinde oluşturulduğu zaman, veya sil(x) yönteminin çalıştırılması sırasında bir düğüm i seviyesinde silindiğinde bu düğüm t[i] tablosundan silinir. Bir karma tabloya değer eklenmesi veya silinmesi sabit beklenen zaman aldığı için, ekle(x) ve sil(x) çalışma zamanlarındaki artış sabit bir faktör ile sınırlıdır. ekle(x) ve sil(x) kod dökümü burada dahil edilmemiştir, çünkü kod listesi İkili Sıralı Ağaç ın yöntemleri ile hemen hemen aynı satırlardan oluşmaktadır. Aşağıdaki teorem X-Hızlı Sıralı Ağaç performansını özetler: Teorem X-Hızlı Sıralı Ağaç w-bit tamsayılar için Sıralı Küme arayüzünü uygular. X-Hızlı Sıralı Ağaç n aşağıdaki işlemleri destekler: İşlem başına O(w) beklenen zamanda çalışan ekle(x), sil(x) ve İşlem başına O(log w) beklenen zamanda çalışan bul(x). değer içeren X-Hızlı Sıralı Ağaç ın kullanması gerekli alan O(n. w) kadardır Y-Hızlı Sıralı Ağaç: Çifte-Logaritmik Zamanlı Sıralı Küme X-Hızlı Sıralı Ağaç, sorgu zamanı açısından İkili Sıralı Ağaç ile kıyaslandığında oldukça büyük hatta üstel bir gelişme sağlar, ancak ekle(x) ve sil(x) işlemleri hala istenildiği kadar hızlı değildir. Ayrıca, alan kullanımı, O(n. w), bu kitapta anlatılan ve kullanım alanı O(n) olan tüm diğer Sıralı Küme uygulamalarından daha yüksektir. Bu iki sorun ilişkilidir; ekle(x) işlemi n kere çalıştırılarak boyutu n. w olan bir yapı oluşturulursa, o zaman ekle(x) işlemi, en azından işlem başına w büyüklüğünde bir zaman (ve alan) gerektirir. Bir sonraki tartışılan Y-Hızlı Sıralı Ağaç, X-Hızlı Sıralı Ağaç ın aynı anda hem alanını azaltır ve hem de hızını artırır. Bir Y-Hızlı Sıralı Ağaç, X-Hızlı Sıralı Ağaç ı, xft, kullanır, ancak xft içinde sadece O(n/w) değer depolar. Bu şekilde, xft tarafından kullanılan toplam alanı sadece 275

276 O(n) olur. Ayrıca, Y-Hızlı Sıralı Ağaç içindeki her w ekle(x) yada sil(x) işleminden sadece biri xft içinde bir ekle(x) veya sil(x) işlemiyle sonuçlanır. Bunu yaparak xft nin ekle(x) ve sil(x) işlemlerine yapılan çağrıların ortalama maliyeti sadece sabittir. Açık soru şudur: xft sadece n/w eleman depoluyorsa, geride kalan n(1 1/w) eleman nereye gider? Bu elemanlar ikincil yapıların içine taşınmıştır, bu durumda genişletilmiş bir treaps versiyonu (Bölüm 7.2) içine gitmiştir. Bu ikincil yapılardan kabaca n/w tane vardır, ortalama olarak, her biri O(w) eleman depolar. Treaps, logaritmik zamanda Sıralı Küme işlemlerini desteklemektedir, böylece bu Treap ler üzerindeki işlemler gerektiği gibi, O(log w) zamanda çalışacaktır. Daha somut olarak, bir Y-Hızlı Sıralı Ağaç bu verilerdeki her elemanın bağımsız olarak 1/w olasılıkla göründüğü bir rasgele örneğini içeren bir X-Hızlı Sıralı Ağaç, xft, içerir. Kolaylık sağlamak için, değer 2w - 1, her zaman xft içindedir. Düşünün ki, xft içinde saklanan elemanlar x0 < x1 <... < xk-1 ile ifade edilsin. O zaman Şekil 13.7 de gösterildiği gibi, her eleman, xi, ile ilişkili, xi 1 + 1,..., xi aralığındaki tüm değerleri depolayan bir treap, ti, vardır. 276

277 Bir Y-Hızlı Sıralı Ağaç içinde bul(x) kullanımı oldukça kolaydır. xft içinde x aranır ve treap, ti, ile ilişkili bazı xi değeri bulunur. Sonra sorguyu cevaplandırmak için treap(x) yöntemi ti için çalıştırılır. (xft üzerinde) ilk bul(x) işlemi O(log w) zamanda çalışır. (treap üzerinde) ikinci bul(x) işlemi, r treap boyutu olarak verildiğinde, O(log r) çalışma zamanı alır. Bu bölümde sonra, treap in beklenen boyutunun O(w) olduğunu göstereceğiz, böylece bu işlem O(log w) çalışma zamanı alacaktır.22 Y-Hızlı Sıralı Ağaç içine bir eleman eklemek de çoğu zaman oldukça kolaydır. Önce x in içine gireceği treap, t, bulunmalıdır. ekle(x) yöntemi xft.bul(x) işlemini çağırır. Daha sonra x, t içine eklenmelidir. Bunu gerçekleştirmek için t.ekle(x) çağrılır. Bu noktada, 1/w olasılığıyla 22 Bu Jensen Eşitsizliği nin bir uygulamasıdır: E[r] = w ise E[log r] log w olur. 277

278 tura gelen ve 1 1/w olasığıyla yazı gelen hileli para fırlatılır. Bu para tura geldiyse, o zaman xft içine x eklenecektir. İşlerin biraz daha karışık hale geldiği yer burasıdır. xft içine x eklendiğinde, treap t iki treaps haline, t1 ve t olmak üzere, ayrılmış olmalıdır. Tüm treap t1 değerleri, x den daha az veya eşittir. Orijinal treap, t, içinden t1 elemanlarının dışında kalan elemanlar ise t içinde depolanır. Bu yapıldıktan sonra, xft içine (x, t1) çifti eklenir. Şekil 13.8 bir örneği göstermektedir. t içine x eklenmesi O(log w) zamanda çalışır. Alıştırma 7.12, t1 ve t halinde t ayrılmasının da O(log w) zamanda yapılabileceğini gösteriyor. xft içine (x, t1) çiftinin eklenmesi O(w) zaman alır, ancak 1/w olasılığıyla gerçekleşir. Bu nedenle, add(x) işleminin beklenen çalışma zamanı olur. sil(x) yöntemi ekle(x) tarafından gerçekleştirilen işleri geri alır. xft.bul(x) cevabını bulmak üzere, xft içinde u, yaprağını buluruz. u dan, x i içeren treap, t yi elde ederiz, ve t den x i sileriz. x, xft de de saklanmışsa (x, 2w 1 e eşit değilse) o zaman xft den x i sileriz ve x'in treap inin içindeki elemanları, bağlantılı listede u nun ardından gelen, t2, treap inin içine ekleriz. Şekil 13.9 da bu gösterilmiştir. 278

279 xft içinde u düğümünü bulma O(log w) beklenen zaman alır. t den x silme O(log w) beklenen zaman alır. Yine, Alıştırma 7.12, t içindeki tüm elemanları t2 içinde birleştirmenin O(log w) zamanda yapılabilir olduğunu göstermektedir. Gerekirse, xft den x i silme O(w) zaman alır, ancak x yalnızca 1/w olasılığı ile xft de yer almaktadır. Bu nedenle, Y-Hızlı Sıralı Ağaç tan bir eleman silmek için beklenen zaman O(log w) olur. Daha önceki tartışmamızda, bu yapının içindeki treap boyutları konusunu bu zamana kadar erteledik. Bu bölümü bitirmeden önce, ihtiyaç duyduğumuz sonucu kanıtlayacağız. 279

280 Önerme x, Y-Hızlı Sıralı Ağaç ta depolanan bir tamsayı olsun ve x i içeren treap, t nin eleman sayısı nx ile göstersin. O zaman E[nx] 2w 1 olur. Kanıt. Şekil a bakın. x1 < x2 < < xi = x < xi+1 < < xn Y-Hızlı Sıralı Ağaç ta depolanan elemanları ifade etsin. Treap t, x e eşit veya daha büyük bazı elemanları içeriyor. Bu elemanlar xi, xi+1,, xi+j-1 ise, xi+j-1 ekle(x) yönteminde fırlatılan hileli paranın tura olarak döndüğü tek elemandır. Diğer bir deyişle, E[j], ilk turayı elde etmek için gereken hileli para fırlatmanın beklenen sayısına eşittir23. Her yazı tura atma bağımsızdır ve tura gelme olasılığı 1/w olarak ortaya çıkıyor, bu nedenle, E[j] w. (w = 2 için, bu durumun bir analizi için Önerme 4.2'ye bakın.) Benzer şekilde, x den daha küçük t elemanları xi 1,, xi k ile veriliyor. Burada ilk k para fırlatma için yazı ve kalan xi k 1 para fırlatmanın sonucu tura gelir. Bu önceki paragrafta ele alınan aynı yazı tura atma deneyi olduğu için, ancak son para fırlatmanın sayılmadığı için bu E[k] w 1 olur. Özetle, nx = j + k, bu nedenle Önerme Y-Hızlı Sıralı Ağaç performansını özetleyen aşağıdaki teoremin kanıtının son parçasıydı: Teorem Y-Hızlı Sıralı Ağaç w-bit tamsayılar için Sıralı Küme arayüzünü uygular. Y-Hızlı Sıralı Ağaç ekle(x), sil(x) ve bul(x) işlemlerini işlem başına O(log w) beklenen zamanda destekler. n değer içeren Y-Hızlı Sıralı Ağaç ın kullanması gerekli alan O(n + w) kadardır. 23 Bu analiz j nin asla n i + 1 değerini aşmayacağı gerçeğini göz ardı ediyor. Ancak, bu sadece E[j] yi azaltır, böylece üst sınır hala geçerlidir. 280

281 Alan gereksinimindeki w terimi xft nin her zaman değer 2w-1 değeri depoladığı gerçeğini anlatıyor. Uygulamada değişiklikler yapılabilir (koda bazı ekstra durumları ekleme pahasına), böylece bu değeri saklamak gereksiz olabilir. Bu durumda, teoremdeki alan gereksinimi O(n) olur Tartışma ve Alıştırmalar ekle(x), sil(x) ve bul(x) işlemlerini O(log w) zamanda gerçekleştiren ilk veri yapısı van Emde Boas tarafından önerilmişti ve o zamandan beri van Emde Boas (ya da Katmanlı) Ağacı [74] olarak bilinir hale gelmiştir. Orijinal van Emde Boas yapısı 2w büyüklüğündeydi, büyük tamsayılar için bu pratik değildi. X-Hızlı Sıralı Ağaç ve Y-Hızlı Sıralı Ağaç veri yapıları Willard [77] tarafından keşfedildi. van Emde Boas ağaçları ile X-Hızlı Sıralı Ağaç yapısı yakından ilgilidir; örneğin, bir X-Hızlı Sıralı Ağaç taki karma tabloları van Emde Boas ağacındaki diziler ile yer değiştirmiştir. Bunun anlamı, karma tablosu t[i] saklamak yerine, van Emde Boas ağacı 2i uzunluğunda bir diziyi saklar. Tamsayıları saklamak için başka bir yapı da Fredman'in ve Willard'ın füzyon ağaçlarıdır [32]. Bu yapı, n adet w-bit tamsayıları O(n) büyüklüğündeki bir alanda saklayabilir, böylece bul(x) işlemi O((log n / (log w)) zamanda çalışır. kullanarak ve olduğunda bir füzyon ağacını olduğunda bir Y-Hızlı Sıralı Ağaç kullanarak O(n) alana gereksinimi olan ve bul(x) işlemini zamanda uygulayabilen bir veri yapısı elde edilir. son zamanlarda Patrascu ve Thorup un alt sınır sonuçları [59] göstermektedir ki, bu sonuçlar, en azından sadece O(n) alan kullanan yapılar için az veya çok en iyidir. Alıştırma Bağlantılı liste yada jump işaretçilerini içermeyen basitleştirilmiş bir İkili Sıralı Ağaç versiyonunu tasarlayın ve uygulayın. bul(x) çalışma zamanı O(w) olmalıdır. 281

282 Alıştırma Hiçbir İkili Sıralı Ağaç kullanmayan basitleştirilmiş bir X-Hızlı Sıralı Ağaç versiyonunu tasarlayın ve uygulayın. Uygulamanız, bunun yerine, bir Çifte Bağlantılı Liste de ve w + 1 karma tabloda her şeyi saklamalıdır. Alıştırma İkili Sıralı Ağaç ı her bit dizisinin kökten-yaprağa bir yol temsil ettiği w uzunluğunda bit dizelerini depolayan bir yapı olarak düşünebiliriz. Değişken uzunluklu dizeleri depolayan ve s uzunluğuna orantılı zamanında ekle(x), sil(x) ve bul(x) işlemlerini gerçekleştiren bir Sıralı Küme uygulaması halinde bu fikri genişletin. İpucu: Veri yapınızdaki her düğüm, karakter değerleri ile endeksli bir karma tablo saklamalıdır. Alıştırma Bir tamsayı x {0,, 2w 1} için, d(x), x ile find(x) tarafından döndürülen değeri arasındaki farkı göstersin [find(x) null döndürürse, o zaman d(x) = 2w olarak tanımlanır]. Örneğin, bul(23) 43 döndürürse, o zaman d(23) = O(1 + log d(x)) beklenen zamanda çalışan bul(x) işleminin değiştirilmiş bir sürümünü X-Hızlı Sıralı Ağaç için tasarlayın ve uygulayın. İpucu: t[w] karma tablosu öyle x değerlerini içerir ki, d(x) = 0, buradan başlamak iyi bir nokta olacaktır. 2. O(1 + log log d(x)) beklenen zamanda çalışan bul(x) işleminin değiştirilmiş bir sürümünü X-Hızlı Sıralı Ağaç için tasarlayın ve uygulayın. 282

283 Bölüm 14 Dış Bellek Aramaları Bu kitap boyunca, Bölüm 1.4 de tanımlandığı gibi w-bit sözcük-ram hesaplama modelini kullanıyorduk. Bu modelin olağan varsayımı, bilgisayarın veri yapısı içindeki tüm verileri depolamak için yeterince büyük bir rasgele erişim belleği olmasıdır. Bazı durumlarda, bu varsayım geçerli değildir. Hiçbir bilgisayarın bunları saklamak için yeterli bellek olmadığı büyük veri koleksiyonları vardır. Bu gibi durumlarda uygulamanın bir sabit disk, bir katı hal diski, hatta bir ağ dosya sunucusu (kendi harici depolaması olan) gibi herhangi bir dış depolama ortamı üzerinde veri depolamaya başvurması gerekir. Harici depolamadan bir elemana erişmek son derece yavaştır. Bu kitabın yazıldığı bilgisayara bağlı sabit diskin 19 ms. ve katı hal sürücünün 0,3 ms. ortalama erişim süresi vardır. Bunun aksine, bilgisayardaki rasgele erişim belleğinin 0, ms. den daha düşük bir ortalama erişim süresi vardır. RAM erişimi, katı hal sürücüsüne erişimden kat daha fazla hızlıdır ve sabit sürücüye erişimden kat daha fazla hızlıdır. Bu hızlar oldukça tipiktir; rasgele bir bayta RAM dan erişmek bir sabit diskten veya katı hal sürücüden rasgele bayta erişmekten binlerce kez daha hızlıdır. Ancak sadece erişim süresi, bütün hikayeyi anlatmıyor. Bir sabit disk veya katı hal diskinden bir bayta eriştiğinizde, diskin bütün bir bloğu okunur. Bilgisayara bağlı sürücülerin her birinin blok boyutu vardır; biz bir bayt okuduğumuzda, sürücü bize her zaman bayt içeren bir blok verir. Dikkatli bir şekilde veri yapısını düzenlersek, bu her disk erişiminin yaptığımız işi tamamlamak için yararlı olabilecek 4,096 bayt verdiği anlamına gelir. Şekil 14.1 de şematik olarak gösterilen dış bellek modeli hesaplamasının arkasındaki fikir budur. Bu modelde, bilgisayarın, tüm verilerin bulunduğu büyük bir dış belleğe erişimi vardır. Bu bellek her biri B sözcük içeren bellek bloklarına ayrılmıştır. Bilgisayar aynı zamanda hesaplamaları gerçekleştirmek için sınırlı bir iç belleğe de sahiptir. İç bellek ve dış bellek arasında bir blok aktarma sabit zaman alır. İç bellek içinde yapılan hesaplamalar bedavadır, 283

284 hiçbir zaman gerektirmezler. İç hafıza hesaplamalarının bedava olması aslında biraz garip gelebilir, ama sadece dış belleğin RAM dan çok daha yavaş olduğu gerçeğini vurgulamaktadır. Tam gelişmiş dış bellek modelinde, iç bellek boyutu da bir parametredir. Ancak, bu bölümde açıklanan veri yapıları için, O(B + logb n) boyutunda bir iç belleğe sahip olmak yeterlidir. Yani, belleğin sabit bir sayıda blokları ve O(logB n) yüksekliğinde bir özyineleme yığınını saklama yeteneğine sahip olması gerekir. Çoğu durumda, bellek gereksinimi için O(B) yeterlidir. Örneğin hatta nispeten küçük bir B=32 değeri ve her n 2160 için, B logb n olur. Onluk tabanda, her için B logb n olur Blok Deposu Dış bellek kavramı çok sayıda olası farklı cihazları içerir; bunların her biri kendine ait bir blok boyutuna sahiptir ve kendi koleksiyonlarına ait sistem çağrıları ile erişilir. Ortak fikirler 284

285 üzerinde odaklanmak üzere bu bölümün anlaşılmasını basitleştirmek için BlokDeposu adında bir nesne ile dış bellek cihazlarını kılıflıyoruz. BlokDeposu, her biri B boyutunda olan bellek bloklarının bir koleksiyonunu saklar. Her blok benzersiz tamsayı endeksi ile tanımlanır. Bir BlokDeposu şu işlemleri destekler: 1. readblock(i): i endeksli bloğun içeriğini döndürür. 2. writeblock(i, b): i endeksli bloğun içeriğini b olarak yazar. 3. placeblock(b): Yeni bir endeks döndürür ve bu endeksin içeriğini b olarak depolar. 4. freeblock(i): i endeksli bloğu serbest bırakır. Bu bloğun içeriğinin artık kullanılmadığı anlamına gelmektedir, bu nedenle bu blok tarafından ayrılan dış bellek yeniden kullanılabilir. BlokDeposu nu düşünmenin en kolay yolu disk üzerinde her biri B bayt içeren bloklara bölünen bir dosyayı depolamanın tasarımlanmasıdır. Bu şekilde, readblock(i) ve writeblock(i, b) bu dosyadan sadece ib,..., (i + 1)B 1 bayt okur ve üzerine yazar. Buna ek olarak basit bir BlokDeposu, kullanıma hazır olan blokların bir serbest listesini tutabilir. freeblock(i) tarafından serbest bırakılan bloklar serbest listesine eklenir. Bu şekilde, placeblock(b) serbest listeden bir blok kullanabilir yada hiçbiri hazır kullanılışlı değilse, dosyanın sonuna yeni bir blok ekler B-Ağaçları Bu bölümde, dış bellek modelinde verimliliği olan ve B-ağaç ları denilen, İkili Ağaç ların bir genellemesini tartışıyoruz. Alternatif olarak, B-ağaç ları, Bölüm 9.1 de anlatılan 2-4 Ağaç larının doğal genellemesi olarak görülebilir. (2-4 Ağaç, B = 2 olarak ayarlanmış B-ağaç ının özel bir durumudur.) Herhangi bir tamsayı B 2 için, B-ağaç ı yaprakların aynı derinliğe sahip olduğu ve kökolmayan her, u, iç düğümünün en az B çocuğu ve en çok 2B çocuğunun olduğu bir ağaçtır. u çocukları bir u.children dizisinde depolanır. Gerekli çocuk sayısı kökte dikkate alınmaz, 2 ve 2B aralığında herhangi bir sayıda olabilir. 285

286 Bir B-Ağaç ının yüksekliği h ise, o zaman B-Ağaç ının yaprak sayısı, l, için şu söylenebilir: İlk eşitsizliğin logaritması alınarak ve terimler yeniden düzenlerek, elde edilir. Yani, bir B-ağaç ın yüksekliği yaprak sayısının B-tabanında logaritması ile orantılıdır. B-ağaç taki her, u, düğümü bir dizi u.keys[0],, u.keys[2b 1] pozisyonlarında anahtar depolar. u, k çocuklu bir iç düğüm ise, o zaman u tarafından depolanan anahtarların sayısı tam olarak k 1 olur ve bunlar u.keys[0],..., u.keys[k 2] pozisyonlarında saklanır. u.keys dizisinin kalan 2B - k + 1 girişleri null olarak ayarlanır. u kök olmayan bir yaprak düğüm ise o zaman, u, B 1 ve 2B 1 arasında bir anahtar değer saklar. B-ağaç ın anahtarları İkili Arama Ağaç ının anahtarlarının benzeridir. k 1 anahtar depolayan her, u, düğümü için, sıralaması geçerlidir. Eğer, u, bir iç düğüm ise, o zaman her i {0,, k 2} için u.keys[i], u.children[i] kökenli altağaçta saklanan her anahtardan daha büyüktür, ancak u.children[i+1] kökenli altağaçta saklanan her anahtardan daha küçüktür. Yani, B=2 olan B-ağaç ına bir örnek Şekil 14.2 de gösterilmektedir. 286

287 B-ağaç ın bir düğümünde saklanan veri boyutunun O(B) olduğuna dikkat edin. Bu nedenle, dış bellek ortamında, B-ağaç ı içindeki B değeri, bir düğüm bir adet dış bellek bloğuna sığacak şekilde seçilmelidir. Bu şekilde, dış bellek modelinde bir B-ağaç işlemini gerçekleştirmek için gereken zaman işlem sırasında erişilen (okunan veya yazılan) düğüm sayısı ile orantılıdır. Örneğin, anahtarlar 4 bayt tamsayı ve düğüm işaretleri de 4 bayt ise, o zaman B = 256 ayarlamasıyla her düğümde bayt veri saklanır. Blok boyutu 4096 bayt olan sabit disk veya bu bölümün başında tartışılan katı hal sürücüsü için bu mükemmel bir B değeri olacaktır. B-ağaç ı ri, uygulayan BAğaç sınıfı, B-ağaç ın düğümlerinin yanı sıra, kök düğümün endeksini, saklayan bir BlokDeposu nu, bs, saklar. Her zamanki gibi, veri yapısındaki eleman sayısını takip etmek için, n tamsayısı, kullanılır: 287

288 Arama Şekil 14.3 te gösterilen bul(x) işleminin uygulanması, İkili Arama Ağacı ndaki bul(x) işleminin genelleştirilmesidir. x için arama kökte başlar ve bir u düğümünün çocuklarının hangisinden aramanın devam edeceğini belirlemek için u düğümünde depolanan anahtarları kullanır. Daha özel olarak ise, bir u düğümünde, arama x in u.keys içinde saklı olduğunu kontrol eder. Eğer öyleyse, x bulunmuştur ve arama tamamlanır. Aksi takdirde, arama u.keys [i]> x olan en küçük, i, tamsayısını bulur, ve u.children[i] kökenli altağaçta arama devam eder. u.keys teki hiçbir anahtar x den büyük değilse, o zaman arama u'nun en sağdaki çocuğundan devam eder. Aynı ikili arama ağaçlarında olduğu gibi, algoritma x den büyük olan en son 288

289 görülen, z, anahtarını izler. x bulunmazsa, x e eşit yada daha fazla olan en küçük değer olarak, z, döndürülür. bul(x) yönteminin merkezinde, null ile doldurulmuş sıralı bir, a, dizisi içinde x değerini arayan findit(a, x) yöntemi bulunmaktadır. Şekil 14.4 de gösterilen bu yöntem, sıralı olarak dizilmiş anahtarların a[0],..., a[k - 1] tarafından temsil edildiği herhangi bir, a, dizisi için ve a[k],..., a[a.length 1] tümü null olarak ayarlandığında çalışır. Eğer x, dizide, i pozisyonunda ise, o zaman findit(a, x) i 1 döndürür. Aksi takdirde, a[i] > x veya a[i] = null olan en küçük, i, endeksini döndürür. findit(a, x) yöntemi her adımda arama alanını yarıya bölen ikili arama kullanır, bu nedenle O(log (a.length )) zamanda çalışır. Bizim ortamımızda, a.length = 2B olduğu için, findit(a, x) çalışma zamanı O(log B) olur. 289

290 B-ağaç bul(x) işleminin çalışma süresini, hem normal sözcük-ram modelinde (her komutu hesaba kattığımız) ve hem de dış bellek modelinde (sadece erişilen düğüm sayısını önemsediğimiz) analiz edebiliriz. B-ağaç içindeki her yaprak en az bir anahtar sakladığı için ve l yapraklı B-ağaç ın yüksekliği O(logBl ) olduğu için, n anahtar saklayan bir B-ağaç ın yüksekliği O(logB n) olur. Bu nedenle, dış bellek modelinde, bul(x) işleminin aldığı zaman O(logB n) olur. Sözcük-RAM modelinde çalışma süresini belirlerken, eriştiğimiz her düğüm için, findit(a, x) çağrı maliyetini hesaba katmalıyız, böylece sözcük-ram modelinde bul(x) işleminin çalışma zamanı olur Ekleme B-ağaç ları ve Bölüm 6.2 de anlatılan İkili Arama Ağacı veri yapısı arasındaki önemli farklardan biri B-ağaç düğümlerinin menşeilerine işaretçi tutmamalarıdır. Bunun nedeni, kısaca açıklanacaktır. Menşei işaretçilerinin eksikliği B-ağaç lar üzerinde ekle(x) ve sil(x) işlemlerinin en kolay özyineleme kullanılarak uygulanması anlamına gelir. Tüm dengeli arama ağaçları gibi, ekle(x) çalışması sırasında bir tür dengeleme gereklidir. Bir B-ağaç ında bu, düğümlerin bölünmesi tarafından yapılır. Şekil 14.5 e bakın. Bölünme iki düzeyli özyineleme ortasında yer almasına rağmen, 2B anahtar içeren ve 2B + 1 çocuk sahibi bir, u, düğümünü alan bir işlem olarak en iyi anlaşılmaktadır. u.children[b],..., u.children[2b] w, u'nun benimsenerek yeni bir, w, düğümü oluşturulur. Yeni düğüm en büyük anahtarlarını u.keys[b],, u.keys[2b 1] alır. Bu noktada, u, B çocuğa ve B anahtara sahiptir. Ekstra anahtar u.keys[b 1], u menşeine kadar geçirilerek w benimsenir. Dikkat etmelisiniz ki, bölme işlemi üç düğüm değiştirir: u, u nun menşei ve yeni düğüm w. B-ağaç düğümlerinin menşei işaretçileri tutmamasının önemli nedeni budur. Sağlasaydı, o zaman w tarafından benimsenen B + 1 çocuğun tüm menşei işaretçilerinin değiştirilmiş 290

291 olması gerekirdi. Bu dış bellek erişimlerin sayısını 3 ten B+4 e artıracaktı ve büyük B değerleri için B-ağaç ları çok daha az etkili olacaktı. B-ağaç ekle(x) yöntemi Şekil 14.6 da gösterilmiştir. Yüksek seviyede bu yöntem, x değerini eklemek için bir, u, yaprağını bulur. Bunun sonucunda B 1 anahtar içerdiği için, u, fazla doluyken, u, bölünür. u'nun menşei fazla doluluk içindeyse, o zaman u menşei de bölünür, bu u nun büyükbabasının fazla doluluk içermesine neden olabilir, ve benzeri. Bu süreç ağaç her seferinde bir seviye yukarı hareket ederek fazla dolu olmayan bir düğüme ulaşana kadar veya kök bölünene kadar devam eder. İlk durumda, işlem durur. Sonraki durumda, iki çocuğu orijinal kök bölündüğü zaman elde edilen düğümler haline gelen yeni bir kök oluşturulur. 291

292 ekle(x) yönteminin kısa özeti, kökten yaprağa x aranır, bulunan yaprağa x eklenir, ve sonra köke dönüş yolunda karşılaşılan herhangi fazla dolu düğümler bölünür. Geliştirdiğimiz bu üst düzey düşünceyle, bu yöntemin özyinelemeli olarak nasıl uygulanabilir olduğunu araştırmayla devam ediyoruz. ekle(x) için gerekli gerçek iş ui tanımlayıcısına sahip u kökenli altağaca x değerini ekleyen, addrecursive(x, ui) yöntemi tarafından yapılıyor. u bir yaprak ise, o zaman x sadece u.keys içine eklenir. Aksi takdirde, özyinelemeli olarak x, uygun u çocuğu içine eklenir. Bu özyinelemeli çağrının sonucu normalde null iken, aynı zamanda u bölündüğü için yeni oluşturulan, w, düğümüne bir referans olabilir. Bu durumda, w, u tarafından benimsenir ve ilk anahtarı alarak u üzerindeki bölme işlemini tamamlar. x değeri eklendikten sonra, (u veya altındaki düğümlerden biri içine) addrecursive(x, ui) yöntemi u tarafından çok fazla anahtar depolandığını (anahtar sayısı en fazla 2B 1 olmalı) 292

293 kontrol eder. Eğer öyleyse, u.split() yöntemine yapılan bir çağrı ile u bölünür. u.split() çağrısının sonucu, addrecursive(x, ui) için dönüş değeri olarak kullanılan yeni bir düğümdür. addrecursive(x, ui) yöntemi, B-ağaç ının köküne bir, x, değeri eklemek için addrecursive(x, ri) çağrısının yapıldığı ekle(x) yöntemini çalıştırır. addrecursive(x, ri) 293

294 kökü bölene kadar giderse, o zaman hem eski kökü ve hem de eski kökün bölünmesiyle oluşturulan yeni düğümü çocukları olarak alan yeni bir kök oluşturulur. ekle(x) ve addrecursive(x, ui) yöntemlerini iki aşamada analiz edebiliriz: Aşağı yönde: Özyinelemenin aşağı aşamasında, x eklenmeden önce, bir dizi BAğaç ı düğümüne erişim sağlanır ve her düğüm üzerinde findit(a, x) çağrısı gerçekleştirilir. bul(x) yönteminde olduğu gibi, bu dış bellek modelinde O(logB n) zaman alır ve sözcük- RAM modelinde O(log n) zamanda çalışır. Yukarı yönde: Özyinelemenin yukarı aşamasında, x eklendikten sonra, bu yöntemler, en fazla bir dizi O(logB n) bölünme gerçekleştirir. Her bölünme sadece üç düğüm içerir, bu nedenle bu aşama dış bellek modelinde O(logB n) zaman alır. Ancak, her bölünme B anahtarın ve çocuklarının bir düğümden diğer düğüme hareket etmesini içerir, böylece bu sözcük-ram modelinde, O(B log n) zaman alır. B değerinin oldukça büyük, hatta log n den çok daha büyük olabildiğini hatırlayın. Bu nedenle, sözcük-ram modelinde, B-ağaç a bir değer eklemek dengeli İkili Arama Ağacı içine eklemekten çok daha yavaş olabilir. Daha sonra Bölüm te, durumun o kadar da kötü olmadığını göstereceğiz; bir ekle(x) çalışması sırasında yapılan bölünme işlemlerinin amortize sayısı sabittir. Bu sözcük-ram modelinde ekle(x) işleminin (amortize) çalışma zamanının O(B + log n) olduğunu gösterir Silme B-ağaç içindeki sil(x) işlemi, yine, en kolay bir özyinelemeli yöntemi olarak uygulanmaktadır. sil(x) işleminin özyinelemeli uygulaması, çeşitli yöntemler arasında karmaşıklığı yaymasına rağmen, Şekil 14.7 de gösterilen genel süreç, oldukça kolaydır. Anahtarların karıştırılıp değiştirilmesiyle silme işlemi, bir, x, değerinin bazı, u, yaprağından çıkarılması problemine indirgenir. x çıkarılmasıyla, u, B 1 anahtar ile bırakılabilir, bu durum alttaşma olarak adlandırılır. 294

295 Bir alttaşma oluştuğunda, u ya kardeşinden anahtar ödünç alır, veya kardeşlerinden biri ile birleşir. u bir kardeş ile birleştiyse, o zaman, u menşei, bir çocuk daha az ve bir anahtar daha az sahibi olacaktır, bu u nun menşeinin de alttaşmasına neden olabilir, bu tekrar, ödünç alma veya birleştirerek düzeltilir, ancak birleştirme u'nun büyükbabasının da alttaşmasına neden olabilir. Bu süreç köke kadar artık alttaşma kalmayana kadar veya kökün son iki çocuğu bir tek çocuk halinde birleştirilene kadar geri dönüş yolunda çalışır. İkinci durum olduğunda, kök kaldırılır ve yalnız olan tek çocuk yeni kök olur. Şimdi, bu adımların her birinin nasıl uygulandığının detaylarını araştıracağız. sil(x) yönteminin ilk işi, çıkarılacak x elemanını bulmaktır. x bir yaprakta bulunursa, o zaman bu yapraktan x kaldırılır. Aksi takdirde, x, eğer bazı iç düğüm, u, için u.keys[i] pozisyonunda bulunursa, o zaman algoritma u.children[i + 1] kökenli altağaçtaki en küçük, x, değerini 295

296 kaldırır. x değeri BAğaç ta saklanan x den daha büyük olan en küçük değerdir. x değeri daha sonra u.keys[i] içindeki x değerini değiştirmek için kullanılır. Bu süreç, Şekil 14.8 de gösterilmiştir. removerecursive(x, ui) yöntemi önceki algoritmanın özyinelemeli bir uygulamasıdır: 296

297 Unutmayın ki, özyinelemeli olarak u nun i'nci çocuğundan x değerini çıkardıktan sonra, bu çocuğun hala en az B 1 anahtarı bulunduğunu removerecursive(x, ui) yönteminin sağlaması gerekmektedir. Önceki kodda, u nun i'nci çocuğunda bir alttaşma olup olmadığını kontrol eden ve bunu düzelten checkunderflow(x, i) adı verilen bir yöntem kullanılarak bu yapılır. u nun i nci çocuğu w olsun. w sadece B 2 anahtara sahipse, o zaman bunun düzeltilmesi gerekir. Düzeltme w nin bir kardeşinin kullanılmasını gerektirir. Bu u nun ya (i + 1) nci çocuğudur, yada (i 1) nci çocuğudur. Genellikle w nin doğrudan solundaki kardeşi, v, olan (i 1) nci çocuğu kullanacağız. Bunun işe yaramadığı sadece bir zaman vardır, i = 0 iken, bu durumda w nin doğrudan sağındaki kardeşi kullanırız. Aşağıda, i 0 durumuna odaklanıyoruz. Burada u nun i'nci çocuğundaki herhangi bir alttaşma u nun (i 1) nci çocuğu yardımı ile düzeltiliyor. i = 0 durumu da benzerdir ve ayrıntıları ekteki kaynak kodunda bulunabilir. 297

298 w düğümündeki bir alttaşmayı düzeltmek için, w için daha fazla anahtar (ve muhtemelen de çocuklar) bulmamız gerekiyor. Bunu yapmanın iki yolu vardır: Ödünç alma: w nin, B 1 anahtardan daha fazlasına sahip olan, v, adında bir kardeşi varsa, o zaman w bazı anahtarları (ve muhtemelen de çocukları) v den ödünç alabilir. Daha spesifik olarak, v, size(v) tane anahtar depoluyorsa o zaman, v ve w, aralarında anahtara sahip olur. Bu nedenle, v den w ye anahtarları kaydırabiliriz, böylece v ve w nin her biri en az B 1 anahtara sahip olacaktır. Bu süreç Şekil 14.9 da gösterilmiştir. 298

299 Birleştirme: Eğer v nin sadece B 1 anahtarı varsa, daha zorlayıcı bir şey yapmamız gerekir, çünkü v herhangi bir anahtarı w ye vermeyi göze alamaz. Bu nedenle, Şekil de gösterildiği gibi v ve w birleştirilir. Birleştirme işlemi bölme işleminin tersidir. 2B 3 toplam anahtar içeren iki düğüm alır ve onları 2B 2 anahtar içeren tek bir düğüm haline birleştirir. (Ek anahtarın gelmesinin nedeni şudur: v ve w yi birleştirdiğimizde, onların ortak menşei u nun şimdi bir daha az çocuğu vardır ve dolayısıyla anahtarlarından birisinden vazgeçmesi gerekiyor.) Özetlemek gerekirse, B-ağaç taki sil(x) yöntemi kökten yaprağa bir yol izler, u, yaprağından bir x anahtarını kaldırır, ve sonra u ve onun atalarını içeren sıfır veya daha fazla birleştirme işlemleri gerçekleştirir, ve en fazla bir ödünç alma işlemi gerçekleştirir. Her birleştirme ve ödünç alma işlemi sadece üç düğüm değiştirmeyi içerdiğinden, ve bu işlemlerin sadece 299

300 O(logB n) kadarı oluştuğundan, dış bellek modelinde tüm süreç O(logB n) çalışma zamanı alır. Yine, her birleştirme ve ödünç alma işlemi sözcük-ram modelinde O(B) zaman almaktadır, bu yüzden (şimdilik) sözcük-ram modelinde sil(x) tarafından gerekli çalışma süresi hakkında söyleyebileceğimiz en fazla şey O(B logb n) olduğudur B-Ağaç ların Amortize Analizi Şimdiye kadar, göstermiştik ki: 1. Dış bellek modelinde, B-ağaç ın bul(x), ekle(x) ve sil(x) işlemlerinin çalışma zamanı O(logB n) olur. 2. Sözcük-RAM modelinde, bul(x) işleminin çalışma zamanı O(log n) ve, ekle(x) ve sil(x) işlemlerinin çalışma zamanı O(B log n) olur. 300

301 Aşağıdaki önerme gösteriyor ki, şimdiye kadar, B-ağaç ları tarafından gerçekleştirilen birleştirme ve bölünme işlemlerinin sayısını olduğundan fazla tahmin ettik. Önerme Boş bir B-ağaç ile başlayarak herhangi bir sırada m adet ekle(x) ve sil(x) işlemlerini yürütürsek en çok 3m/2 kadar bölünme, birleştirme, ve ödünç alma gerçekleştirilir. Kanıt. Bunun kanıtı zaten Bölüm 9.3 te, B = 2 özel durumu için, kısaca anlatılmıştı. Önerme kredi düzeni kullanılarak kanıtlanabilir. Burada, 1. her bölme, birleştirme, ya da ödünç alma işlemi iki kredi ile ödenir, yani, bu işlemlerin biri oluştuğunda her zaman bir kredi kaldırılır; ve 2. herhangi ekle(x) veya sil(x) işlemi sırasında en çok üç kredi oluşturulur. Herhangi bir zamanda en çok 3m kredi oluşturulduğu için ve her bir bölünme, birleştirme ve ödünç alma iki kredi ile ödendiği için en çok 3m/2 bölünme, birleştirme, ve ödünç alma yapıldığı sonucuna varırız. Bu krediler Şekil 14.5, 14.9 ve olarak sembolü kullanılarak gösterilmektedir. Bu kredileri takip etmek için kanıt aşağıdaki kredi değişmeyenini korur: B 1 anahtara sahip kök-olmayan bir düğüm bir kredi depolar ve 2B-1 anahtarlı herhangi bir düğüm üç kredi saklar. En az B anahtar ve en çok 2B 2 anahtar depolayan bir düğümün herhangi bir kredi saklaması gerekmez. Geriye kalan yapmamız gereken, kredi değişmeyenini korumak olduğunu göstermek ve her ekle(x) ve sil(x) işlemi sırasında, yukarıda verilen, 1. ve 2. özellikleri sağlamaktır. Ekleme: ekle(x) yöntemi herhangi bir birleştirme veya ödünç alma gerçekleştirmez, bu nedenle sadece ekle(x) için yapılan aramaların bir sonucu olarak ortaya çıkan bölünme işlemlerini dikkate almamız gerekiyor. Her bölünme işlemi gerçekleştiğinde zaten 2B 1 anahtar içeren bir, u, düğümüne bir anahtar eklenir. Bu durumda, u, B 1 anahtar içeren u, ve B anahtar içeren u düğümü olmak üzere iki düğüme ayrılmıştır. Bu işlem öncesinde, u, 2B - 1 anahtar ve dolayısıyla üç kredi saklıyordu. Bu kredilerin ikisi bölünmeyi ödemek için kullanılabilir ve diğer kredi, kredi 301

302 değişmeyenini korumak için (B 1 anahtara sahip olan) u düğümüne verilebilir. Bu nedenle, bölünme için ödeme yapabiliriz ve herhangi bir bölünme sırasında kredi değişmeyenini koruyabiliriz. Bir ekle(x) işlemi sırasında meydana gelen düğümler için sadece yapılan diğer değişiklik, bütün bölünmeler, varsa, tamamlandığında olur. Bu değişiklik, bazı u düğümüne yeni bir anahtar eklenmesini içerir. Eğer, bunun öncesinde u düğümünün 2B 2 çocuğu vardıysa, şimdi 2B 1 çocuk sahibidir ve bu nedenle üç kredi almak zorundadır. Bu ekle(x) yöntemi ile dağıtılan yalnız ve tek kredidir. Silme: sil(x) için yapılan bir çağrı sırasında sıfır veya daha fazla birleştirme meydana gelir ve muhtemelen bunu tek bir ödünç alma izler. Her birleştirme, sil(x) çağrısı öncesinde her biri tam olarak B 1 anahtar sahibi iki düğümün, v ve w, tam olarak 2B 2 anahtara sahip tek bir düğüm haline birleştirilmesi nedeniyle oluşur. Bu türde her birleştirme, bu nedenle, birleştirmeyi ödemek için kullanılabilecek olan iki krediyi serbest bırakır. Herhangi bir birleştirme yapıldıktan sonra, en fazla bir ödünç alma işlemi gerçekleşir, daha sonra başka hiçbir birleştirme yada ödünç alma meydana gelmez. Bu ödünç alma işlemi sadece B 1 anahtara sahip bir, v, yaprağından bir anahtarı kaldırırsak oluşur. v düğümü bu nedenle bir krediye sahiptir, ve bu kredi ödünç alma maliyetine doğru gider. Bu tek kredi ödünç almayı ödemek için yeterli değildir, bu nedenle ödemeyi tamamlamak için bir kredi yaratırız. Bu noktada, bir kredi yarattık ve hala kredi değişmeyeninin korunabilir olduğunu göstermemiz gerekiyor. En kötü durumda, v nin, kardeşi, w, ödünç almadan önce tam olarak B anahtara sahiptir, böylece, daha sonra, v ve w, her ikisinin de B 1 anahtarı olacaktır. Bunun anlamı, işlem tamamlandığında v ve w, her ikisi de kredi depoluyor olması gerekir. Bu nedenle, bu durumda, v ve w ye vermek için ek iki kredi oluştururuz. Bir sil(x) çalışması sırasında en fazla bir kez ödünç alma olduğu için bu, gerektiği gibi en çok üç kredi yarattığımız anlamına gelir. sil(x) işlemi ödünç alma işlemi içermiyorsa, bunun nedeni, işlemden önce B veya daha fazla anahtarı olan bazı düğümden bir anahtar çıkararak bitirdiği içindir. En kötü durumda, bu 302

303 düğümün, tam olarak B anahtarı vardı, öyle ki şimdi B 1 anahtarı bulunuyor ve yarattığımız bir kredi verilmelidir. Her iki durumda da silme ödünç alma ile işini bitirse de veya bitirmese de sil(x) için yapılan bir çağrı sırasında kredi değişmeyenini korumak ve meydana gelen tüm ödünç alma ve birleştirmelerin ödemesini yapmak için en fazla üç kredi yaratılmalıdır. Bu önermenin kanıtını tamamlar. Önerme 14.1 in amacı sözcük-ram modelinde, m adet ekle(x) ve sil(x) işlemi sırasında gerçekleştirilen bölünme ve birleştirmelerin çalışma zamanı sadece O(Bm) olduğunu göstermektir. Yani, işlem başına amortize edilmiş maliyet sadece O(B) olur, böylece sözcükram modelinde ekle(x) ve sil(x) amortize maliyeti O(B + log n) olur. Aşağıdaki teorem çifti bunu özetliyor: Teorem 14.1 (Dış Bellek B-Ağaç ları). BAğaç, Sıralı Küme arayüzünü uygular. Dış Bellek modelinde, BAğaç, işlem başına O(logB n) zamanda çalışan ekle(x), sil(x), ve bul(x) işlemlerini destekler. Teorem 14.2 (Sözcük-RAM B-Ağaç ları). BAğaç, Sıralı Küme arayüzünü uygular. SözcükRAM modelinde, bölünmeler, birleştirmeler, ve ödünç almaların maliyetini gözardı ederek, BAğaç, işlem başına O(log n) zamanda çalışan ekle(x), sil(x), ve bul(x) işlemlerini destekler. Boş bir BAğaç ile başlayarak herhangi bir sırada m adet ekle(x) ve sil(x) işlemlerini yürütürsek bölünme, birleştirme, ve ödünç almaları gerçekleştirmek için gerekli zaman toplamda O(Bm) olur Tartışma ve Alıştırmalar Hesaplamanın dış bellek modeli Aggarwal ve Vitter tarafından tanıtıldı [4]. Bazen I/O modeli veya disk erişimi modeli de denir. İkili Arama Ağaç ları içsel bellek araması için ne ise, B-ağaç lar için de dış bellek araması odur. B-ağaç ları [9] 1970 yılında Bayer ve McCreight tarafından tanıtıldı ve on yıldan daha 303

304 az bir süre sonra, Comer ACM Bilgisayar Anketleri makalesi onları her yerde hazır bulunan olarak anmıştır [15]. İkili Arama Ağaç ları gibi, B-Ağaç ların B+ ağaçları, B* ağaçları, ve sayılan B-ağaçları dahil olmak üzere birçok çeşidi vardır. B-ağaç ları, gerçekten her yerde vardır ve Apple'ın HFS+, Microsoft'un NTFS, ve Linux Ext4 dahil olmak üzere birçok dosya sistemlerinde; her büyük veritabanı sisteminde; ve anahtar-değer saklayan bulut bilişimde birincil veri yapısıdır. Graefe nin en son anketi [36] birçok modern uygulamalar, varyantları, ve B-ağaç larının optimizasyonları üzerine 200+ sayfa bir bakış sağlar. B-Ağaç ları Sıralı Küme arayüzünü uygular. Yalnızca Sırasız Küme arayüzü gerekli ise, dış bellek karma yöntemi B-ağaç larının bir alternatifi olarak kullanılabilir. Dış bellek karma tasarımları vardır; bakınız örneğin, Jensen ve Pagh [43]. Bu tasarımlar Sırasız Küme işlemlerini dış bellek modelinde O(1) beklenen zamanda uygular. Bununla birlikte, çeşitli nedenlerden dolayı, birçok uygulama sadece Sırasız Küme işlemlerini gerektiriyor olsa bile hala B-ağaç larını kullanmaktadır. B-ağaç larını böyle popüler bir seçim yapan nedenlerden biri genellikle önerilen O(logB n) çalışma süresi sınırlarından daha iyi performans gösteriyor olmasıdır. Bunun nedeni, dış bellek ortamlarında B değeri genellikle oldukça büyüktür yüzler hatta binler cinsinden. Bunun anlamı, B-ağaç ı verilerinin % 99, hatta % 99.9 kadarı yapraklarda depolanır. Büyük bir belleğe sahip bir veritabanı sisteminde, bir B-ağaç ın RAM deki tüm iç düğümlerini önbelleğe almak mümkün olabilir, çünkü toplam veri setinin sadece %1 veya %0.1 kadarını temsil ederler. Bu durumda, bunun anlamı bir B-ağaç RAM içinde iç düğümler aracılığıyla, ve bunu takiben bir yaprak bulup getirmek için tek bir dış bellek erişimiyle çok hızlı bir arama gerçekleştirebilir. Alıştırma ,5 ve 7,5 anahtarlarının Şekil 14.2 deki B-ağaç ına eklendiğinde ne olduğunu gösterin. Alıştırma ve 4 anahtarlarının Şekil 14.2 deki B-ağaç ından silindiğinde ne olduğunu gösterin. 304

305 Alıştırma n anahtar saklayan bir B-ağaç ının iç düğümlerinin maksimum sayısı nedir? (n ve B fonksiyonu olarak) Alıştırma Bu bölümün giriş kısmında B-ağaç larının sadece O(B + logb n) boyutunda içsel belleğe ihtiyaçları olduğu öne sürülmüştü. Ancak, burada verilen uygulama gerçekte daha fazla bellek gerektirir. 1. Bu bölümde verilen ekle(x) ve sil(x) yöntemlerinin uygulamasının O(B logb n) ile orantılı içsel bellek kullandığını gösterin. 2. Bu yöntemlerin bellek tüketimini O(B + logb n) düzeyine azaltmak amacıyla nasıl değiştirilebileceklerini açıklayın. Alıştırma Önerme 14.1 in Şekil 14.6 ve 14.7 deki ağaçlar üzerindeki kanıtında kullanılan kredileri yazın. bölünme, birleştirme, ödünç alma ve kredi değişmeyenini korumanın (üç ek kredi ile) ödenmesinin mümkün olduğunu doğrulayın. Alıştırma Düğümleri B den 3B ye kadar çocuk (ve dolayısıyla B 1 den 3B 1 e kadar sayıda anahtar) sahibi olan B-ağaç ın değiştirilmiş bir sürümünü tasarlayın. B-ağaç ların bu yeni versiyonunun, m işlem dizisi sırasında sadece O(m/ B) bölünme, birleştirme ve ödünç alma gerçekleştirdiğini gösterin. Alıştırma Bu uygulamada, B-ağaç larında bölünme ve birleştirmenin değiştirilmiş bir yöntemini tasarlayacaksınız. Bu yöntem, bir anda üç düğüme kadar dikkate alarak, bölünme, ödünç alma ve birleştirme sayısını asimptotik olarak azaltıyor. 1. u fazla dolu bir düğüm ve v, u nun hemen sağındaki kardeş olsun. u taşmasını düzeltmek için iki yol vardır: a) u anahtarlarından bazılarını v ye verebilir; veya b) u bölünebilir ve, u ve v anahtarları u, v ve yeni oluşturulan w düğümü arasında eşit olarak dağıtılabilir, 305

306 Bu işlem sonrasında etkilenen düğümlerin her birinin (en fazla 3 adet) herhangi bir sabit için en az ve en çok anahtar sahibi olduğunu gösterin. 2. u az dolu bir düğüm ve, v ve w, u nun kardeşleri olsun. u alttaşmasını düzeltmek için iki yol vardır: a) anahtarlar u, v ve w arasında dağıtılabilir; veya b) u, v, ve w iki düğüm halinde birleştirilir ve u, v ve w anahtarları bu düğümler arasında dağıtılabilir. Bu işlem sonrasında etkilenen düğümlerin her birinin (en fazla 3 adet) herhangi bir sabit için en az ve en çok anahtar sahibi olduğunu gösterin. 3. Bu değişiklikler ile, m işlem sırasında gerçekleştirilen birleştirme, ödünç alma, ve bölünme sayısının O(m/B) olduğunu gösterin. Alıştırma Şekil de gösterilen B+-Ağaç ı her bir anahtarı bir yaprakta tutar ve yaprakları Çifte-Bağlantılı Liste olarak depolar. Her zamanki gibi, her yaprak B 1 ve 2B 1 arası bir sayıda anahtar saklar. Sonuncusu dışında her yaprağın en büyük değerini saklayan standart bir B-ağaç ı bu listenin yukarısında yer almaktadır. 1. B+-Ağaç için ekle(x), sil(x) ve bul(x) uygulamalarının hızlı bir şekilde nasıl gerçekleştirilebileceğini anlatın. 2. B+-Ağaç içinde x ten daha büyük ve y den daha küçük veya eşit tüm değerleri bildiren findrange(x, y) yönteminin verimli olarak nasıl uygulanacağını açıklayın. 306

307 3. bul(x), ekle(x), sil(x) ve findrange(x, y) işlemlerini gerçekleştiren bir BPlusTree sınıfı uygulayın. 4. B+-Ağaç ları bazı anahtarları çoğaltırlar çünkü hem B-ağaç ında ve hem de listede her ikisinde de saklanır. Bu çoğaltmanın, B nin büyük değerleri için neden çok fazla pahalı olmadığını açıklayın. 307

308 KAYNAKÇA 308

309 309

310 310

311 311

312 312

313 313

314 314

315 315

AÇIK VERİ YAPILARI (JAVA İLE )

AÇIK VERİ YAPILARI (JAVA İLE ) AÇIK VERİ YAPILARI (JAVA İLE ) ATTRIBUTION (LISANS): HTTP://CREATIVECOMMON S.ORG/LICENSES/BY/4.0 RESIDING LOCATION (ADRESI): HTTPS://ARCHIVE.ORG/DET AILS/OST-COMPUTER- SCIENCE-ODS-JAVA Açık Veri Yapıları

Detaylı

BİL-341 ALGORİTMALAR BÜYÜK O NOTASYONU AHMET ATAKAN 0904.01036. atakanahmet@hotmail.com KIRGIZİSTAN-TÜRKİYE MANAS ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ

BİL-341 ALGORİTMALAR BÜYÜK O NOTASYONU AHMET ATAKAN 0904.01036. atakanahmet@hotmail.com KIRGIZİSTAN-TÜRKİYE MANAS ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ BİL-341 ALGORİTMALAR BÜYÜK O NOTASYONU AHMET ATAKAN 0904.01036 atakanahmet@hotmail.com KIRGIZİSTAN-TÜRKİYE MANAS ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ BİŞKEK 2012 Ahmet Atakan

Detaylı

6.046J/18.401J DERS 7 Kıyım Fonksiyonu (Hashing I) Prof. Charles E. Leiserson

6.046J/18.401J DERS 7 Kıyım Fonksiyonu (Hashing I) Prof. Charles E. Leiserson Algoritmalara Giriş 6.046J/8.40J DERS 7 Kıyım Fonksiyonu (Hashing I) Doğrudan erişim tabloları Çarpışmaları ilmekleme ile çözmek Kıyım fonksiyonu seçimi Açık adresleme Prof. Charles E. Leiserson October

Detaylı

Algoritma Geliştirme ve Veri Yapıları 9 Ağaç Veri Modeli ve Uygulaması. Mustafa Kemal Üniversitesi

Algoritma Geliştirme ve Veri Yapıları 9 Ağaç Veri Modeli ve Uygulaması. Mustafa Kemal Üniversitesi Algoritma Geliştirme ve Veri Yapıları 9 Ağaç Veri Modeli ve Uygulaması Ağaç, verilerin birbirine sanki bir ağaç yapısı oluşturuyormuş gibi sanal olarak bağlanmasıyla elde edilen hiyararşik yapıya sahip

Detaylı

ELN1002 BİLGİSAYAR PROGRAMLAMA 2

ELN1002 BİLGİSAYAR PROGRAMLAMA 2 ELN1002 BİLGİSAYAR PROGRAMLAMA 2 VERİ YAPILARI Sunu Planı Kendini-gösteren Yapılar Dinamik Bellek Tahsisi Bağlı Listeler Yığınlar Kuyruklar Ağaçlar 1 Veri Yapıları Şu ana kadar, diziler, matrisler ve yapılar

Detaylı

ELN1001 BİLGİSAYAR PROGRAMLAMA I

ELN1001 BİLGİSAYAR PROGRAMLAMA I ELN1001 BİLGİSAYAR PROGRAMLAMA I DEPOLAMA SINIFLARI DEĞİŞKEN MENZİLLERİ YİNELEMELİ FONKSİYONLAR Depolama Sınıfları Tanıtıcılar için şu ana kadar görülmüş olan özellikler: Ad Tip Boyut Değer Bunlara ilave

Detaylı

Algoritmalar ve Karmaşıklık

Algoritmalar ve Karmaşıklık Algoritmalar ve Karmaşıklık Ders 11 Algoritma Ayrık matematikte karşılaşılan bir çok problem sınıfı mevcuttur. Örneğin, verilen tamsayı grubu içindeki en büyük olanının bulunması, verilen bir kümenin bütün

Detaylı

Yrd. Doç. Dr. A. Burak İNNER Bilgisayar Mühendisliği

Yrd. Doç. Dr. A. Burak İNNER Bilgisayar Mühendisliği Yrd. Doç. Dr. A. Burak İER Bilgisayar Mühendisliği Algoritma Analizi İçerik: Temel Kavramlar Yinelemeli ve Yinelemesiz Algoritma Analizi Asimptotik otasyonlar Temel Kavramlar Algoritma: Bir problemin çözümüne

Detaylı

BULANIK MANTIK VE SİSTEMLERİ 2014 2015 BAHAR DÖNEMİ ÖDEV 1. Müslüm ÖZTÜRK 148164001004 Bilişim Teknolojileri Mühendisliği ABD Doktora Programı

BULANIK MANTIK VE SİSTEMLERİ 2014 2015 BAHAR DÖNEMİ ÖDEV 1. Müslüm ÖZTÜRK 148164001004 Bilişim Teknolojileri Mühendisliği ABD Doktora Programı BULANIK MANTIK VE SİSTEMLERİ 2014 2015 BAHAR DÖNEMİ ÖDEV 1 Müslüm ÖZTÜRK 148164001004 Bilişim Teknolojileri Mühendisliği ABD Doktora Programı Mart 2015 0 SORU 1) Bulanık Küme nedir? Bulanık Kümenin (fuzzy

Detaylı

Veri Yapıları Laboratuvarı

Veri Yapıları Laboratuvarı 2013 2014 Veri Yapıları Laboratuvarı Ders Sorumlusu: Yrd. Doç. Dr. Hakan KUTUCU Lab. Sorumlusu: Arş. Gör. Caner ÖZCAN İÇİNDEKİLER Uygulama 1: Diziler ve İşaretçiler, Dinamik Bellek Ayırma... 4 1.1. Amaç

Detaylı

Göstericiler (Pointers)

Göstericiler (Pointers) C PROGRAMLAMA Göstericiler (Pointers) C programlama dilinin en güçlü özelliklerinden biridir. Göstericiler, işaretçiler yada pointer adı da verilmektedir. Gösterici (pointer); içerisinde bellek adresi

Detaylı

Excel Nedir? Microsoft Excell. Excel de Çalışma sayfası-tablo

Excel Nedir? Microsoft Excell. Excel de Çalışma sayfası-tablo Microsoft Excell Excel Nedir? Excel programı; veriler üzerinde hesap yapabilme, verileri tabloya dönüştürebilme, verileri karşılaştırıp sonuç üretebilme, grafik oluşturma, veri yönetimi yapabilir. http://mf.dpu.edu.tr/~eyup

Detaylı

Microsoft Excel. Çalışma Alanı. Hızlı Erişim Çubuğu Sekmeler Başlık Formül Çubuğu. Ad Kutusu. Sütunlar. Satırlar. Hücre. Kaydırma Çubukları

Microsoft Excel. Çalışma Alanı. Hızlı Erişim Çubuğu Sekmeler Başlık Formül Çubuğu. Ad Kutusu. Sütunlar. Satırlar. Hücre. Kaydırma Çubukları Microsoft Excel Microsoft Excel yazılımı bir hesap tablosu programıdır. Excel, her türlü veriyi (özellikle sayısal verileri) tablolar ya da listeler halinde tutma ve bu verilerle ilgili ihtiyaç duyacağınız

Detaylı

Ayrık Fourier Dönüşümü

Ayrık Fourier Dönüşümü Ayrık Fourier Dönüşümü Tanım: 0 n N 1 aralığında tanımlı N uzunluklu bir dizi x[n] nin AYRIK FOURIER DÖNÜŞÜMÜ (DFT), ayrık zaman Fourier dönüşümü (DTFT) X(e jω ) nın0 ω < 2π aralığında ω k = 2πk/N, k =

Detaylı

Algoritmaların Karşılaştırılması. Doç. Dr. Aybars UĞUR

Algoritmaların Karşılaştırılması. Doç. Dr. Aybars UĞUR Algoritmaların Karşılaştırılması Doç. Dr. Aybars UĞUR Giriş Bir programın performansı genel olarak programın işletimi için gerekli olan bilgisayar zamanı ve belleğidir. Bir programın zaman karmaşıklığı

Detaylı

Genel Programlama II

Genel Programlama II Genel Programlama II 22.03.2011 1 Yapılar ( Structures ) Yapılar ( structures ); tam sayı, karakter vb. veri tiplerini gruplayıp, tek bir çatı altında toplar. Bu gruplandırma içinde aynı ya da farklı veri

Detaylı

Algoritma Geliştirme ve Veri Yapıları 3 Veri Yapıları. Mustafa Kemal Üniversitesi

Algoritma Geliştirme ve Veri Yapıları 3 Veri Yapıları. Mustafa Kemal Üniversitesi Algoritma Geliştirme ve Veri Yapıları 3 Veri Yapıları Veri yapısı, bilginin anlamlı sırada bellekte veya disk, çubuk bellek gibi saklama birimlerinde tutulması veya saklanması şeklini gösterir. Bilgisayar

Detaylı

YZM ALGORİTMA ANALİZİ VE TASARIM DERS#2: ALGORİTMA ANALİZİ

YZM ALGORİTMA ANALİZİ VE TASARIM DERS#2: ALGORİTMA ANALİZİ YZM 3207- ALGORİTMA ANALİZİ VE TASARIM DERS#2: ALGORİTMA ANALİZİ Algoritma Analizi Çerçevesi Algoritma Analizinde Göz Önünde Bulundurulması Gerekenler Neler? Algoritmanın Doğruluğu (Correctness) Zaman

Detaylı

Yrd. Doç. Dr. Caner ÖZCAN

Yrd. Doç. Dr. Caner ÖZCAN Yrd. Doç. Dr. Caner ÖZCAN Derse Giriş Ders Web Sitesi: www.canerozcan.net Ofis Saatleri: Salı 11:00-13:00 Perşembe 15:30-17:30 ya da email ile randevu alınız: canerozcan@karabuk.edu.tr Kaynak Kitaplar:

Detaylı

ALGORİTMA VE PROGRAMLAMA II

ALGORİTMA VE PROGRAMLAMA II ALGORİTMA VE PROGRAMLAMA II Yrd. Doç. Dr. Deniz KILINÇ deniz.kilinc@cbu.edu.tr YZM 1102 Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi Genel Bakış 2 Bellek ve Adresleme İşaretçi Kavramı

Detaylı

Dr. Fatih AY Tel: 0 388 225 22 55 fatihay@fatihay.net www.fatihay.net

Dr. Fatih AY Tel: 0 388 225 22 55 fatihay@fatihay.net www.fatihay.net Bilgisayar Programlama Ders 6 Dr. Fatih AY Tel: 0 388 225 22 55 fatihay@fatihay.net www.fatihay.net Fonksiyon Prototipleri Fonksiyon Prototipleri Derleyici, fonksiyonların ilk hallerini (prototiplerini)

Detaylı

Örnek 4: Örnek Özyinelemeli fonksiyon örneği Bölüm 9. C++ programlama dilinde Nesne ve sınıf

Örnek 4: Örnek Özyinelemeli fonksiyon örneği Bölüm 9. C++ programlama dilinde Nesne ve sınıf İçindekiler 1. Giriş... 1 1.2. c++ Programı Yapısı... 2 1.3.Using Direktifi... 5 Bölüm 2. Veri türleri, değişken kavramı, sabit ve değişken bildirimleri ve c++ da kullanımı 7 2.1. Temel veri türleri...

Detaylı

Bil101 Bilgisayar Yazılımı I. M. Erdem ÇORAPÇIOĞLU Bilgisayar Yüksek Mühendisi

Bil101 Bilgisayar Yazılımı I. M. Erdem ÇORAPÇIOĞLU Bilgisayar Yüksek Mühendisi Bil101 Bilgisayar Yazılımı I Bilgisayar Yüksek Mühendisi Editör Disk 1)Kaynak kodlar editör aracılığı ile oluşturulur. (.c) Kaynak dosya Önişleyici Disk 2)Önişleyici kodlar içerisindeki ilk işleme işini

Detaylı

MATEMATiKSEL iktisat

MATEMATiKSEL iktisat DİKKAT!... BU ÖZET 8 ÜNİTEDİR BU- RADA İLK ÜNİTE GÖSTERİLMEKTEDİR. MATEMATiKSEL iktisat KISA ÖZET KOLAY AOF Kolayaöf.com 0362 233 8723 Sayfa 2 içindekiler 1.ünite-Türev ve Kuralları..3 2.üniteTek Değişkenli

Detaylı

11.Konu Tam sayılarda bölünebilme, modüler aritmetik, Diofant denklemler

11.Konu Tam sayılarda bölünebilme, modüler aritmetik, Diofant denklemler 11.Konu Tam sayılarda bölünebilme, modüler aritmetik, Diofant denklemler 1. Asal sayılar 2. Bir tam sayının bölenleri 3. Modüler aritmetik 4. Bölünebilme kuralları 5. Lineer modüler aritmetik 6. Euler

Detaylı

MAK 210 SAYISAL ANALİZ

MAK 210 SAYISAL ANALİZ MAK 210 SAYISAL ANALİZ BÖLÜM 2- HATA VE HATA KAYNAKLARI Doç. Dr. Ali Rıza YILDIZ 1 GİRİŞ Bir denklemin veya problemin çözümünde kullanılan sayısal yöntem belli bir giriş verisini işleme tabi tutarak sayısal

Detaylı

Özyineleme (Recursion)

Özyineleme (Recursion) C PROGRAMLAMA Özyineleme (Recursion) Bir fonksiyonun kendisini çağırarak çözüme gitmesine özyineleme (recursion), böyle çalışan fonksiyonlara da özyinelemeli (recursive) fonksiyonlar denilir. Özyineleme,

Detaylı

DİZİLER-KATARLAR ALGORİTMA VE PROGRAMLAMA II

DİZİLER-KATARLAR ALGORİTMA VE PROGRAMLAMA II DİZİLER-KATARLAR ALGORİTMA VE PROGRAMLAMA II DİZİLER Dizi, aynı tipteki verilere tek bir isimle erişmek için kullanılan bir kümedir. Bir dizi bildirildikten sonra, dizinin bütün elemanları bellekte peşpeşe

Detaylı

How to ASP Language. Elbistan Meslek Yüksek Okulu 2011 2012 Bahar Yarıyılı. Öğr. Gör. Murat KEÇECĠOĞLU. 29 Eki. 1 Kas. 2013

How to ASP Language. Elbistan Meslek Yüksek Okulu 2011 2012 Bahar Yarıyılı. Öğr. Gör. Murat KEÇECĠOĞLU. 29 Eki. 1 Kas. 2013 How to ASP Language Elbistan Meslek Yüksek Okulu 2011 2012 Bahar Yarıyılı 29 Eki. 1 Kas. 2013 Öğr. Gör. Murat KEÇECĠOĞLU Fonksiyonlar, kendilerini göreve çağıran VBScript komutlarına ve işlemlerine bir

Detaylı

ELN1002 BİLGİSAYAR PROGRAMLAMA 2

ELN1002 BİLGİSAYAR PROGRAMLAMA 2 ELN1002 BİLGİSAYAR PROGRAMLAMA 2 SIRALAMA ALGORİTMALARI Sunu Planı Büyük O Notasyonu Kabarcık Sıralama (Bubble Sort) Hızlı Sıralama (Quick Sort) Seçimli Sıralama (Selection Sort) Eklemeli Sıralama (Insertion

Detaylı

Excel Formüller ve Fonksiyonlar. Yusuf MANSUROĞLU Mühendislik Hizmetleri Müdür Yardımcısı 11.02.2015

Excel Formüller ve Fonksiyonlar. Yusuf MANSUROĞLU Mühendislik Hizmetleri Müdür Yardımcısı 11.02.2015 Excel Formüller ve Fonksiyonlar Yusuf MANSUROĞLU Mühendislik Hizmetleri Müdür Yardımcısı 11.02.2015 Excel de Yapabileceklerimiz Temel aritmetik işlemler (4 işlem) Mantıksal karşılaştırma işlemleri (>,>=,

Detaylı

C Dersleri Bölüm 3 : Program akışı

C Dersleri Bölüm 3 : Program akışı İzmir Ekonomi Üniversitesi Bilgisayar Topluluğu www.ieubt.org C Dersleri Bölüm 3 : Program akışı Sorularınız için : programlama@ieubt.org Hazırlayan : Görkem PAÇACI (gorkem.pacaci@std.ieu.edu.tr) C Program

Detaylı

UZAKTAN EĞİTİM MERKEZİ

UZAKTAN EĞİTİM MERKEZİ ÜNİTE 2 VERİ TABANI İÇİNDEKİLER Veri Tabanı Veri Tabanı İle İlgili Temel Kavramlar Tablo Alan Sorgu Veri Tabanı Yapısı BAYBURT ÜNİVERSİTESİ UZAKTAN EĞİTİM MERKEZİ BİLGİSAYAR II HEDEFLER Veri tabanı kavramını

Detaylı

VERİ MADENCİLİĞİ. Karar Ağacı Algoritmaları: SPRINT algoritması Öğr.Gör.İnan ÜNAL

VERİ MADENCİLİĞİ. Karar Ağacı Algoritmaları: SPRINT algoritması Öğr.Gör.İnan ÜNAL VERİ MADENCİLİĞİ Karar Ağacı Algoritmaları: SPRINT algoritması Öğr.Gör.İnan ÜNAL SPRINT Algoritması ID3,CART, ve C4.5 gibi algoritmalar önce derinlik ilkesine göre çalışırlar ve en iyi dallara ayırma kriterine

Detaylı

VERİ YAPILARI LİSTELER. Yrd. Doç. Dr. Murat GÖK Bilgisayar Mühendisliği Bölümü YALOVA ÜNİVERSİTESİ

VERİ YAPILARI LİSTELER. Yrd. Doç. Dr. Murat GÖK Bilgisayar Mühendisliği Bölümü YALOVA ÜNİVERSİTESİ VERİ YAPILARI LİSTELER Yrd. Doç. Dr. Murat GÖK Bilgisayar Mühendisliği Bölümü YALOVA ÜNİVERSİTESİ Bağlı Listeler Aynı kümeye ait veri parçalarının birbirlerine bellek üzerinde, sanal olarak bağlanmasıyla

Detaylı

Pointer Kavramı. Veri Yapıları

Pointer Kavramı. Veri Yapıları Pointer Kavramı Veri Yapıları Pointer Kavramı- Pointer Nedir? Göstericiler, işaretçiler ya da pointer adı da verilmektedir. Gösterici (pointer); içerisinde bellek adresi tutan değişkenlerdir. Şu ana kadar

Detaylı

MIT OpenCourseWare http://ocw.mit.edu. 14.30 Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009

MIT OpenCourseWare http://ocw.mit.edu. 14.30 Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009 MIT OpenCourseWare http://ocw.mit.edu 14.30 Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009 Bu materyale atıfta bulunmak ve kullanım koşulları için http://ocw.mit.edu/terms sayfasını ziyaret ediniz.

Detaylı

b) Algoritmanızın en kötü durumda işlem zamanını asimptotik olarak bulunuz

b) Algoritmanızın en kötü durumda işlem zamanını asimptotik olarak bulunuz 2014 Soru 1. (15 puan) 5,2,4,1,15,8,11,13,7,6 dizisinin elemanlarından maksimum özellikli bir yığın(heap) oluşturulmasını adım adım yazınız. Heapsort algoritmasının yardımıyla yapılacak sıralamayı anlatınız.

Detaylı

SAYISAL ÇÖZÜMLEME. Yrd.Doç.Dr.Esra Tunç Görmüş. 1.Hafta

SAYISAL ÇÖZÜMLEME. Yrd.Doç.Dr.Esra Tunç Görmüş. 1.Hafta SAYISAL ÇÖZÜMLEME Yrd.Doç.Dr.Esra Tunç Görmüş 1.Hafta Sayısal çözümleme nümerik analiz nümerik çözümleme, approximate computation mühendislikte sayısal yöntemler Computational mathematics Numerical analysis

Detaylı

ÜNİTE 9 ÜNİTE 9 MICROSOFT EXCEL - II TEMEL BİLGİ TEKNOLOJİLERİ İÇİNDEKİLER HEDEFLER

ÜNİTE 9 ÜNİTE 9 MICROSOFT EXCEL - II TEMEL BİLGİ TEKNOLOJİLERİ İÇİNDEKİLER HEDEFLER ÜNİTE 9 MICROSOFT EXCEL - II BAYBURT ÜNİVERSİTESİ UZAKTAN EĞİTİM MERKEZİ İÇİNDEKİLER Çalışma sayfasına yeni nesneler eklemek Veriler ile ilgili işlemler Grafikler ler Sıralama Yapmak Filtreleme Yapmak

Detaylı

BIL222 Veri Yapıları ve Algoritmalar

BIL222 Veri Yapıları ve Algoritmalar BIL222 Veri Yapıları ve Algoritmalar 1. ĠKĠLĠ AĞAÇLAR (BIARY TREES) Bütün düğümlerinin derecesi en fazla iki olan ağaca ikili ağaç denir. Yani bir düğüme en fazla iki tane düğüm bağlanabilir ( çocuk sayısı

Detaylı

Temel Bilgisayar Programlama Final Sınavı Çalışma Notları

Temel Bilgisayar Programlama Final Sınavı Çalışma Notları Diziler Temel Bilgisayar Programlama Final Sınavı Çalışma Notları (Dr. Övünç ÖZTÜRK, Dr. Tahir Emre KALAYCI) (İnşaat Mühendisliği ve Gıda Mühendisliği Grupları İçin) Diziler aynı türden bilgileri saklamak

Detaylı

2. REGRESYON ANALİZİNİN TEMEL KAVRAMLARI Tanım

2. REGRESYON ANALİZİNİN TEMEL KAVRAMLARI Tanım 2. REGRESYON ANALİZİNİN TEMEL KAVRAMLARI 2.1. Tanım Regresyon analizi, bir değişkenin başka bir veya daha fazla değişkene olan bağımlılığını inceler. Amaç, bağımlı değişkenin kitle ortalamasını, açıklayıcı

Detaylı

2 ALGORİTMA VE AKIŞ DİYAGRAMLARI

2 ALGORİTMA VE AKIŞ DİYAGRAMLARI İÇİNDEKİLER IX İÇİNDEKİLER 1 GİRİŞ 1 Kitabın Amacı 1 Algoritmanın Önemi 2 Bilgisayarın Doğuşu ve Kullanım Amaçları 3 Programlama Dili Nedir? 3 Entegre Geliştirme Ortamı (IDE) Nedir? 4 2 ALGORİTMA VE AKIŞ

Detaylı

Aynı tipten çok sayıda değişken topluluğudur. X Y Score1 Score2 (0) (1) (2)...

Aynı tipten çok sayıda değişken topluluğudur. X Y Score1 Score2 (0) (1) (2)... Array (Diziler) Array Aynı tipten çok sayıda değişken topluluğudur. Birden fazla aynı tipteki değerle işlem yapmayı kolaylaştırır. X Y Score1 Score2 40 56 Grade 40 56 80 (0) (1) (2)... (13) Array tanımlama:

Detaylı

Bilgisayar Teknolojileri Bölümü Bilgisayar Programcılığı Programı. Öğr. Gör. Cansu AYVAZ GÜVEN

Bilgisayar Teknolojileri Bölümü Bilgisayar Programcılığı Programı. Öğr. Gör. Cansu AYVAZ GÜVEN Bilgisayar Teknolojileri Bölümü Bilgisayar Programcılığı Programı Öğr. Gör. Cansu AYVAZ GÜVEN NESNE TABANLI PROGRAMLAMA Java Değişkenler ve Veri Tipleri Operatörler JAVA Java Java SUN bilgisayar şirketince

Detaylı

Toplama işlemi için bir ikili operatör olan artı işareti aynı zamanda tekli operatör olarak da kullanılabilir.

Toplama işlemi için bir ikili operatör olan artı işareti aynı zamanda tekli operatör olarak da kullanılabilir. www.csharpturk.net Türkiye nin C# Okulu Yazar Yunus Özen Eposta yunus@yunus.gen.tr Tarih 08.04.2006 Web http://www.yunusgen.tr ARİTMETİK OPERATÖRLER VE KULLANIM ŞEKİLLERİ Bilgisayarlar yapıları gereği,

Detaylı

15.433 YATIRIM. Ders 3: Portföy Teorisi. Bölüm 1: Problemi Oluşturmak

15.433 YATIRIM. Ders 3: Portföy Teorisi. Bölüm 1: Problemi Oluşturmak 15.433 YATIRIM Ders 3: Portföy Teorisi Bölüm 1: Problemi Oluşturmak Bahar 2003 Biraz Tarih Mart 1952 de, Şikago Üniversitesi nde yüksek lisans öğrencisi olan 25 yaşındaki Harry Markowitz, Journal of Finance

Detaylı

6.Hafta Kıyım Fonksiyonu (Hashing), BST. Doğrudan erişim tabloları Çarpışmaları ilmekleme ile çözmek Kıyım fonksiyonu seçimi Açık adresleme

6.Hafta Kıyım Fonksiyonu (Hashing), BST. Doğrudan erişim tabloları Çarpışmaları ilmekleme ile çözmek Kıyım fonksiyonu seçimi Açık adresleme 1 6.Hafta Kıyım Fonksiyonu (Hashing), BST Doğrudan erişim tabloları Çarpışmaları ilmekleme ile çözmek Kıyım fonksiyonu seçimi Açık adresleme Sembol-tablosu problemi 2 Doğrudan erişim tablosu 3 4 Çözüm

Detaylı

Bilgisayarda Programlama. Temel Kavramlar

Bilgisayarda Programlama. Temel Kavramlar Bilgisayarda Programlama Temel Kavramlar KAVRAMLAR Programlama, yaşadığımız gerçek dünyadaki problemlere ilişkin çözümlerin bilgisayarın anlayabileceği bir biçime dönüştürülmesi / ifade edilmesidir. Bunu

Detaylı

Algoritmalar. Arama Problemi ve Analizi. Bahar 2016 Doç. Dr. Suat Özdemir 1

Algoritmalar. Arama Problemi ve Analizi. Bahar 2016 Doç. Dr. Suat Özdemir 1 Algoritmalar Arama Problemi ve Analizi Bahar 2016 Doç. Dr. Suat Özdemir 1 Arama Problemi Sıralama algoritmaları gibi arama algoritmaları da gerçek hayat bilgisayar mühendisliği problemlerinin çözümünde

Detaylı

İnternet Programcılığı Öğr. Gör. Serkan AKSU PHP de Dizi-Değişkenler, Nesneler. Dizi Oluşturma. Tek Boyutlu Diziler

İnternet Programcılığı Öğr. Gör. Serkan AKSU  PHP de Dizi-Değişkenler, Nesneler. Dizi Oluşturma. Tek Boyutlu Diziler PHP de Dizi-Değişkenler, Nesneler Dizilerle ilgili örneklere geçmeden önce aşağıdaki tabloyu inceleyelim. Tabloda dizi kavramının mantığı açıklanmaktadır. Tablonun tamamını bir dizi olarak düşünün ve bu

Detaylı

1 PROGRAMLAMAYA GİRİŞ

1 PROGRAMLAMAYA GİRİŞ İÇİNDEKİLER IX İÇİNDEKİLER 1 PROGRAMLAMAYA GİRİŞ 1 Problem Çözme 1 Algoritma 1 Algoritmada Olması Gereken Özellikler 2 Programlama Dilleri 6 Programlama Dillerinin Tarihçesi 6 Fortran (Formula Translator)

Detaylı

(Random-Access Memory)

(Random-Access Memory) BELLEK (Memory) Ardışıl devreler bellek elemanının varlığı üzerine kuruludur Bir flip-flop sadece bir bitlik bir bilgi tutabilir Bir saklayıcı (register) bir sözcük (word) tutabilir (genellikle 32-64 bit)

Detaylı

Bilgisayar Programlama MATLAB

Bilgisayar Programlama MATLAB What is a computer??? Bilgisayar Programlama MATLAB Prof. Dr. İrfan KAYMAZ What Konular is a computer??? MATLAB ortamının tanıtımı Matlab sistemi (ara yüzey tanıtımı) a) Geliştirme ortamı b) Komut penceresi

Detaylı

HSancak Nesne Tabanlı Programlama I Ders Notları

HSancak Nesne Tabanlı Programlama I Ders Notları DİZİLER Bellekte ard arda yer alan aynı türden nesneler kümesine dizi (array) denilir. Bir dizi içerisindeki bütün elemanlara aynı isimle ulaşılır. Yani dizideki bütün elemanların isimleri ortaktır. Elemanlar

Detaylı

İstatistik ve Olasılık

İstatistik ve Olasılık İstatistik ve Olasılık Rastgele Değişkenlerin Dağılımları I Prof. Dr. İrfan KAYMAZ Ders konusu Bu derste; Rastgele değişkenlerin tanımı ve sınıflandırılması Olasılık kütle fonksiyonu Olasılık yoğunluk

Detaylı

Max - Min Heap Tree (Max ve Min Yığıt Ağaçları) Veri Yapıları ve Algoritmalar 2 - Mustafa EGE Ders Notları

Max - Min Heap Tree (Max ve Min Yığıt Ağaçları) Veri Yapıları ve Algoritmalar 2 - Mustafa EGE Ders Notları Max - Min Heap Tree (Max ve Min Yığıt Ağaçları) Veri Yapıları ve Algoritmalar 2 - Mustafa EGE Ders Notları Max - Min Heap Öncelikli kuyruk konusunu hatırlayın. Kuyruğa sonradan eklenmesine rağmen öncelik

Detaylı

JAVA PROGRAMLAMA DİLİ ÖZELLİKLERİ

JAVA PROGRAMLAMA DİLİ ÖZELLİKLERİ JAVA PROGRAMLAMA DİLİ ÖZELLİKLERİ Java programlama dili, Java SUN bilgisayar şirketi tarafından 1991 yılında geliştiril Program bloklar halinde yazılır ve bloklar { } ile oluşturulur. Komutlar aynı satıra

Detaylı

ELEKTRONİK TABLOLAMA Aritmetiksel işlemler ve mantısal karşılaştırmaların yapıldığı programlar elektronik tablolama programlarıdır.

ELEKTRONİK TABLOLAMA Aritmetiksel işlemler ve mantısal karşılaştırmaların yapıldığı programlar elektronik tablolama programlarıdır. ELEKTRONİK TABLOLAMA Aritmetiksel işlemler ve mantısal karşılaştırmaların yapıldığı programlar elektronik tablolama programlarıdır. Günümüzde yaygın olarak kullanılan elektronik tablolama programlarından

Detaylı

f(x) ve g(x) reel sayılarda tanımlı iki fonksiyon olmak üzere, x > k olacak şekilde bir k vardır öyle ki,

f(x) ve g(x) reel sayılarda tanımlı iki fonksiyon olmak üzere, x > k olacak şekilde bir k vardır öyle ki, Algoritma Karmaşıklığı ve Büyük O Gösterimi (Big O Notation) Yazdığımız bir algoritmanın doğru çalıştığından emin olmakla birlikte bu algoritmayı, daha önce yazılmış ve aynı sonucu veren başka algoritmalarla

Detaylı

C# Programlama Dili. İlk programımız Tür dönüşümü Yorum ekleme Operatörler

C# Programlama Dili. İlk programımız Tür dönüşümü Yorum ekleme Operatörler C# Programlama Dili İlk programımız Tür dönüşümü Yorum ekleme Operatörler 1 İlk Programımız Bu program konsol ekranına Merhaba dünya! yazıp kapanır. Programı geçen derste anlatıldığı gibi derleyin, sonra

Detaylı

HACETTEPE ÜNİVERSİTESİ BAHAR DÖNEMİ

HACETTEPE ÜNİVERSİTESİ BAHAR DÖNEMİ Öğrenci Adı Soyadı: Öğrenci Numarası: S1 S2 S3 S4 S5 S6 S7 Toplam HACETTEPE ÜNİVERSİTESİ 2012-2013 BAHAR DÖNEMİ BİLGİSAYAR MÜHENDİSLİĞİ BÖLÜMÜ BBM202 Algoritmalar 1. Ara Sınav 25.04.2013 Sınav Süresi:

Detaylı

MIT OpenCourseWare Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009

MIT OpenCourseWare Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009 MIT OpenCourseWare http://ocw.mit.edu 14.30 Ekonomide İstatistiksel Yöntemlere Giriş Bahar 2009 Bu materyale atıfta bulunmak ve kullanım koşulları için http://ocw.mit.edu/terms sayfasını ziyaret ediniz.

Detaylı

ÜNİT E ÜNİTE GİRİŞ. Algoritma Mantığı. Algoritma Özellikleri PROGRAMLAMA TEMELLERİ ÜNİTE 3 ALGORİTMA

ÜNİT E ÜNİTE GİRİŞ. Algoritma Mantığı. Algoritma Özellikleri PROGRAMLAMA TEMELLERİ ÜNİTE 3 ALGORİTMA PROGRAMLAMA TEMELLERİ ÜNİTE 3 ALGORİTMA GİRİŞ Bilgisayarların önemli bir kullanım amacı, veri ve bilgilerin kullanılarak var olan belirli bir problemin çözülmeye çalışılmasıdır. Bunun için, bilgisayarlar

Detaylı

T.C. MALTEPE ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ YAZILIM MÜHENDİSLİĞİ LİSANS PROGRAMI. 2011-12 Bahar Yarıyılı

T.C. MALTEPE ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ YAZILIM MÜHENDİSLİĞİ LİSANS PROGRAMI. 2011-12 Bahar Yarıyılı T.C. MALTEPE ÜNİVERSİTESİ MÜHENDİSLİK FAKÜLTESİ YAZILIM MÜHENDİSLİĞİ LİSANS PROGRAMI 2011-12 Bahar Yarıyılı ALGORİTMA VE PROGRAMLAMA BİL 133 5 AKTS Kredisi 1. yıl 1. yarıyıl Lisans Zorunlu 4 saat/hafta

Detaylı

F(A, N, K) // A dizi; N, K integer if N<0 then return K; if A[N]>K then K = A[N]; return F(A, N-1, K);

F(A, N, K) // A dizi; N, K integer if N<0 then return K; if A[N]>K then K = A[N]; return F(A, N-1, K); 2009-2010 BAHAR DÖNEMİ MC 689 ALGORİTMA TASARIMI ve ANALİZİ I. VİZE ÇÖZÜMLERİ 1. a) Böl ve yönet (divide & conquer) tarzındaki algoritmaların genel özelliklerini (çalışma mantıklarını) ve aşamalarını kısaca

Detaylı

Algoritmalara Giriş Ekim 17, 2005 Massachusetts Institute of Technology Profesörler Erik D. Demaine ve Charles E. Leiserson Dağıtım 15.

Algoritmalara Giriş Ekim 17, 2005 Massachusetts Institute of Technology Profesörler Erik D. Demaine ve Charles E. Leiserson Dağıtım 15. Algoritmalara Giriş Ekim 17, 2005 Massachusetts Institute of Technology 6.046J/18.410J Profesörler Erik D. Demaine ve Charles E. Leiserson Dağıtım 15 Problem Seti 4 Okumalar: Bölüm 12 13 ve 18 Hem egzersizler

Detaylı

Veritabanı Tasarımı. Düzenli İfadeler

Veritabanı Tasarımı. Düzenli İfadeler Veritabanı Tasarımı Düzenli İfadeler Konular Düzenli ifadeleri tanımlama SQL ifadelerinde düzenli ifadeleri arama, eşleme ve yer değiştirme katarlarında kullanma Düzenli ifadeleri ve kontrol kısıtlamalarını

Detaylı

BLM-112 PROGRAMLAMA DİLLERİ II. Ders-1 Kapsama Kuralları & Rasgele Sayı Üretimi & Rekürsif (Özyinelemeli) Fonksiyonlar

BLM-112 PROGRAMLAMA DİLLERİ II. Ders-1 Kapsama Kuralları & Rasgele Sayı Üretimi & Rekürsif (Özyinelemeli) Fonksiyonlar BLM-112 PROGRAMLAMA DİLLERİ II Ders-1 Kapsama Kuralları & Rasgele Sayı Üretimi & Rekürsif (Özyinelemeli) Fonksiyonlar Yrd. Doç. Dr. Ümit ATİLA umitatila@karabuk.edu.tr http://web.karabuk.edu.tr/umitatilla/

Detaylı

Java, Python ve Ruby Dillerinin Performans Karşılaştırması

Java, Python ve Ruby Dillerinin Performans Karşılaştırması Java, Python ve Ruby Dillerinin Performans Karşılaştırması Çanakkale Onsekiz Mart Üniversitesi Mustafa ŞAHİN Akademik Bilişim 2007 1 Dillerin seçim nedeni Java, Pyton ve Ruby Programlama dillerinin popülerliği

Detaylı

ALGORİTMA VE PROGRAMLAMA I DERS NOTU#8

ALGORİTMA VE PROGRAMLAMA I DERS NOTU#8 ALGORİTMA VE PROGRAMLAMA I DERS NOTU#8 YZM 1105 Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi 6. BÖLÜM 2 Çok Boyutlu Diziler Çok Boyutlu Dizi 3 Bir dizi aşağıdaki gibi bildirildiğinde

Detaylı

Türev Uygulamaları ÜNİTE. Amaçlar. İçindekiler. Yazar Prof.Dr. Vakıf CAFEROV

Türev Uygulamaları ÜNİTE. Amaçlar. İçindekiler. Yazar Prof.Dr. Vakıf CAFEROV Türev Uygulamaları Yazar Prof.Dr. Vakıf CAFEROV ÜNİTE 10 Amaçlar Bu üniteyi çalıştıktan sonra; türev kavramı yardımı ile fonksiyonun monotonluğunu, ekstremum noktalarını, konvekslik ve konkavlığını, büküm

Detaylı

Bir işaretli büyüklük sayısında en soldaki basamak bir işaret içerir. Diğer basamaklarda ise sayısal değerin büyüklüğü (mutlak değeri) gösterilir.

Bir işaretli büyüklük sayısında en soldaki basamak bir işaret içerir. Diğer basamaklarda ise sayısal değerin büyüklüğü (mutlak değeri) gösterilir. İşaretli Tamsayı Gösterimi 1. İşaretli Büyüklük Bir işaretli büyüklük sayısında en soldaki basamak bir işaret içerir. Diğer basamaklarda ise sayısal değerin büyüklüğü (mutlak değeri) gösterilir. Örnek

Detaylı

PHP, nesne-yönelimli (object-oriented) bir dil olduğu için, nesne oluşturma imkânına ve bunların kullanılmasını sağlayan metodlara da sahiptir.

PHP, nesne-yönelimli (object-oriented) bir dil olduğu için, nesne oluşturma imkânına ve bunların kullanılmasını sağlayan metodlara da sahiptir. PHP'nin Temelleri PHP Nedir? PHP, bir programlama dili olarak, değişkenler, değişkenlerin değerleriyle bir işlem yapmayı sağlayan işlemciler (operatörler), işlemcilerle oluşturulan deyimler ve nihayet

Detaylı

NESNEYE YÖNELİK PROGRAMLAMA

NESNEYE YÖNELİK PROGRAMLAMA NESNEYE YÖNELİK PROGRAMLAMA Metotlar Şu ana kadar yaptığımız örneklerde hep önceden hazırlanmış ReadLine(), WriteLine() vb. gibi metotları kullandık. Artık kendi metotlarımızı yapmanın zamanı geldi. Bilmem

Detaylı

BLM-112 PROGRAMLAMA DİLLERİ II. Ders-7 Sıralama Algoritmaları

BLM-112 PROGRAMLAMA DİLLERİ II. Ders-7 Sıralama Algoritmaları BLM-112 PROGRAMLAMA DİLLERİ II Ders-7 Sıralama Algoritmaları Yrd. Doç. Dr. Ümit ATİLA umitatila@karabuk.edu.tr http://web.karabuk.edu.tr/umitatilla/ Sıralama Bir grup veriyi azalan veya artan şekilde yerleştirme.

Detaylı

ALGORİTMA VE PROGRAMLAMA I

ALGORİTMA VE PROGRAMLAMA I ALGORİTMA VE PROGRAMLAMA I Yrd. Doç. Dr. Deniz KILINÇ deniz.kilinc@cbu.edu.tr YZM 1101 Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi Genel Bakış 2 Diziler Dizi Nedir? Dizilerin Bildirimi

Detaylı

BMB204. Veri Yapıları Ders 12. Dizgi Eşleme (String Matching) Algoritmaları İleri Veri Yapıları

BMB204. Veri Yapıları Ders 12. Dizgi Eşleme (String Matching) Algoritmaları İleri Veri Yapıları BMB204. Veri Yapıları Ders 12. Dizgi Eşleme (String Matching) Algoritmaları İleri Veri Yapıları Erdinç Uzun NKÜ Çorlu Mühendislik Fakültesi Bilgisayar Mühendisliği Bölümü Dersin Planı Dizgi Eşleme Algoritmaları

Detaylı

Uzaktan Eğitim Uygulama ve Araştırma Merkezi

Uzaktan Eğitim Uygulama ve Araştırma Merkezi JAVA PROGRAMLAMA Öğr. Gör. Utku SOBUTAY İÇERİK 2 Java da Fonksiyon Tanımlamak Java da Döngüler Java da Şart İfadeleri Uygulamalar Java da Fonksiyon Tanımlamak JAVA DA FONKSİYON TANIMLAMAK 4 Fonksiyonlar;

Detaylı

Çoktan Seçmeli Değerlendirme Soruları Akış Şemaları İle Algoritma Geliştirme Örnekleri Giriş 39 1.Gündelik Hayattan Algoritma Örnekleri 39 2.Say

Çoktan Seçmeli Değerlendirme Soruları Akış Şemaları İle Algoritma Geliştirme Örnekleri Giriş 39 1.Gündelik Hayattan Algoritma Örnekleri 39 2.Say İÇİNDEKİLER 1. Bilgisayarın Yapısı Ve Programlama Dilleri Giriş 1 Bilgisayar ve Programlamanın Kısa Bir Tarihçesi 2 Donanım ve Yazılım Kavramları 3 Bilgisayarın Donanımsal yapısı 4 Giriş Birimi (Input

Detaylı

Değişkenler. Geçerli değişken isimleri : baslamazamani, ad_soyad, x5 Geçersiz değişken isimleri : 3x, while

Değişkenler. Geçerli değişken isimleri : baslamazamani, ad_soyad, x5 Geçersiz değişken isimleri : 3x, while Değişkenler Değişkenler bir bilginin bellekteki konumunu temsil eden sembolik isimlerdir. Bilgisayarda hemen hemen tüm işlemler bellekte yapılır. Program çalıştırıldığında değişken ve bu değişkenin türüne

Detaylı

ANADOLU ÜNİVERSİTESİ AÇIKÖĞRETİM FAKÜLTESİ İLKÖĞRETİM ÖĞRETMENLİĞİ LİSANS TAMAMLAMA PROGRAMI. Analiz. Cilt 2. Ünite 8-14

ANADOLU ÜNİVERSİTESİ AÇIKÖĞRETİM FAKÜLTESİ İLKÖĞRETİM ÖĞRETMENLİĞİ LİSANS TAMAMLAMA PROGRAMI. Analiz. Cilt 2. Ünite 8-14 ANADOLU ÜNİVERSİTESİ AÇIKÖĞRETİM FAKÜLTESİ İLKÖĞRETİM ÖĞRETMENLİĞİ LİSANS TAMAMLAMA PROGRAMI Analiz Cilt 2 Ünite 8-14 T.C. ANADOLU ÜNİVERSİTESİ YAYINLARI NO: 1082 AÇIKÖĞRETİM FAKÜLTESİ YAYINLARI NO: 600

Detaylı

AYRIK YAPILAR ARŞ. GÖR. SONGÜL KARAKUŞ- FIRAT ÜNİVERSİTESİ TEKNOLOJİ FAKÜLTESİ YAZILIM MÜHENDİSLİĞİ BÖLÜMÜ, ELAZIĞ

AYRIK YAPILAR ARŞ. GÖR. SONGÜL KARAKUŞ- FIRAT ÜNİVERSİTESİ TEKNOLOJİ FAKÜLTESİ YAZILIM MÜHENDİSLİĞİ BÖLÜMÜ, ELAZIĞ AYRIK YAPILAR P r o f. D r. Ö m e r A k ı n v e Y r d. D o ç. D r. M u r a t Ö z b a y o ğ l u n u n Ç e v i r i E d i t ö r l ü ğ ü n ü ü s t l e n d i ğ i «A y r ı k M a t e m a t i k v e U y g u l a

Detaylı

C#(Sharp) Programlama Dili

C#(Sharp) Programlama Dili Değişkenler C#(Sharp) Programlama Dili Program yazarken her zaman sabit verilerle çalışmayız, çoğu zaman programımızda bir verinin kullanıcının davranışına göre değişmesi gerekir. Kullanıcıdan bir metin

Detaylı

Klavyeden Basit Giriş/Çıkış İşlemleri

Klavyeden Basit Giriş/Çıkış İşlemleri Klavyeden Basit Giriş/Çıkış İşlemleri Klavyeden veri girilmesi, girilen verilere çeşitli işlemler uygulandıktan sonra ekrana yazdırılması ya da herhangi bir yazıcıdan çıktı alınması gibi işlemlerdir. Javada

Detaylı

Yrd. Doç. Dr. Caner ÖZCAN

Yrd. Doç. Dr. Caner ÖZCAN Yrd. Doç. Dr. Caner ÖZCAN Diziler ile Pointer Arası İlişki Bir dizi adı sabit bir pointer gibi düşünülebilir. Diziler ile pointer lar yakından ilişkilidir. Pointer lar değişkenleri gösterdikleri gibi,

Detaylı

ALGORİTMA VE PROGRAMLAMA I

ALGORİTMA VE PROGRAMLAMA I ALGORİTMA VE PROGRAMLAMA I YZM 1101 Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi Genel Bakış 2 Karakter Dizileri Karakter Dizilerini Okumak ve Yazmak Karakter Dizilerinin Uzunluğunu

Detaylı

ALGORİTMA ANALİZİ. Cumhuriyet Üniversitesi Bilgisayar Mühendisliği Bölümü

ALGORİTMA ANALİZİ. Cumhuriyet Üniversitesi Bilgisayar Mühendisliği Bölümü ALGORİTMA ANALİZİ Cumhuriyet Üniversitesi Bilgisayar Mühendisliği Bölümü 2 Temel Kavramlar Algoritma: Bir problemin çözümünü belirli bir zamanda çözmek için sonlu sayıdaki adım-adım birbirini takip eden

Detaylı

BLM 112- Programlama Dilleri II. Hafta 4 İşaretçiler (Pointers)

BLM 112- Programlama Dilleri II. Hafta 4 İşaretçiler (Pointers) 1 BLM 112- Programlama Dilleri II Hafta 4 İşaretçiler (Pointers) Dr. Öğr. Üyesi Caner Özcan İyilik insanları birbirine bağlayan altın zincirdir. ~Goethe Hafıza Yapısı 2 Bir değişken tanımlandığında arka

Detaylı

BÖLÜM 24 PAULI SPİN MATRİSLERİ

BÖLÜM 24 PAULI SPİN MATRİSLERİ BÖLÜM 24 PAULI SPİN MATRİSLERİ Elektron spini için dalga fonksiyonlarını tanımlamak biraz kullanışsız görünüyor. Çünkü elektron, 3B uzayda dönmek yerine sadece kendi berlirlediği bir rotada dönüyor. Elektron

Detaylı

Veri Yapıları. Amaçlar: Temel Veri Yapılarını Tanımlamalı Veri Yapılarını Veri Modeli ve Türlerini Öğreneceksiniz. İçindekiler:

Veri Yapıları. Amaçlar: Temel Veri Yapılarını Tanımlamalı Veri Yapılarını Veri Modeli ve Türlerini Öğreneceksiniz. İçindekiler: Veri Yapıları Amaçlar: Temel Veri Yapılarını Tanımlamalı Veri Yapılarını Veri Modeli ve Türlerini Öğreneceksiniz İçindekiler: Giriş Temel Veri Yapıları Tanımlamalı Veri Yapıları Veri Modeli ve Türleri

Detaylı

ALGORİTMA VE PROGRAMLAMA I

ALGORİTMA VE PROGRAMLAMA I ALGORİTMA VE PROGRAMLAMA I YZM 1101 Celal Bayar Üniversitesi Hasan Ferdi Turgutlu Teknoloji Fakültesi Genel Bakış 2 Diziler Dizi Nedir? Dizilerin Bildirimi Dizilere Başlangıç Değeri Verme Dizilerde Arama

Detaylı

İŞLETMELERDE BECERİ EĞİTİMİ DERSİ MİCROSOFT WORD 2007 ÇALIŞMALARI

İŞLETMELERDE BECERİ EĞİTİMİ DERSİ MİCROSOFT WORD 2007 ÇALIŞMALARI 1 2 3 Microsoft Office Word Belgesinde çalışmamızı tamamladıktan sonra simgesine tıkladığımızda açılan menüde dosyamızı kaydedebiliriz veya yazıcıdan çıktısını alabiliriz. Çalışmamızda değişiklik yapmak

Detaylı

BLM 112- Programlama Dilleri II. Hafta 5 İşaretçiler (Pointers)

BLM 112- Programlama Dilleri II. Hafta 5 İşaretçiler (Pointers) 1 BLM 112- Programlama Dilleri II Hafta 5 İşaretçiler (Pointers) Dr. Öğr. Üyesi Caner Özcan Hiç hata yapmayan insan, hiçbir şey yapmayan insandır. Ve hayatta en büyük hata, kendini hatasız sanmaktır. ~Y.

Detaylı

HEDEF ARA ve ÇÖZÜCÜ HEDEF ARA

HEDEF ARA ve ÇÖZÜCÜ HEDEF ARA HEDEF ARA ve ÇÖZÜCÜ HEDEF ARA Hedef ara komutu bir fonksiyonun tersinin bulunmasında kullanılır. Hedef ara işlemi, y=f(x) gibi bir fonksiyonda y değeri verildiğinde x değerinin bulunmasıdır. Bu işlem,

Detaylı

İleri Diferansiyel Denklemler

İleri Diferansiyel Denklemler MIT AçıkDersSistemi http://ocw.mit.edu 18.034 İleri Diferansiyel Denklemler 2009 Bahar Bu bilgilere atıfta bulunmak veya kullanım koşulları hakkında bilgi için http://ocw.mit.edu/terms web sitesini ziyaret

Detaylı

Görsel Programlama DERS 04. Görsel Programlama - Ders04/ 1

Görsel Programlama DERS 04. Görsel Programlama - Ders04/ 1 Görsel Programlama DERS 04 Görsel Programlama - Ders04/ 1 Diziler ve Kolleksiyonlar(Collections) Diziler aynı tipli değişkenleri tutmak için kullanılan veri yapılarıdır. Diziler sabit uzunlukludur. Birkez

Detaylı

18.034 İleri Diferansiyel Denklemler

18.034 İleri Diferansiyel Denklemler MIT AçıkDersSistemi http://ocw.mit.edu 18.034 İleri Diferansiyel Denklemler 2009 Bahar Bu bilgilere atıfta bulunmak veya kullanım koşulları hakkında bilgi için http://ocw.mit.edu/terms web sitesini ziyaret

Detaylı