Transkript
MIT Açık Ders malzemeleri
6.046J Algoritmalara Giriş, Güz 2005
Bu materyallerden alıntı yapmak veya kullanım şartları hakkında bilgi
almak için:
Erik
Demaine ve Charles Leiserson, 6.046J Introduction to Algorithms, Fall
2005. (Massachusetts Institute of Technology: MIT OpenCourseWare).
http://ocw.mit.edu
(Giriş Tarihi:
08, 01, 2010).
Lisans: Creative Commons Attribution-Noncommercial-Share Alike.
Not: Lütfen atıf taparken bilgilere eriştiğiniz gerçek tarihi
kullanınız.
Atıflar ve Kullanım Koşulları konusunda daha fazla bilgi için:
http://ocw.mit.edu/terms
ve http://www.acikders.org.tr
sitesini ziyaret ediniz.
Ders 10
Günaydın. Öyle görünüyor ki sabah 9:30 herkes için daha
erken olmaya başladı. Evden bizi izleyen herkese merhaba.. Bence şöyle
bir kural olmalı: Eğer bizi videodan izlemek isterseniz bunu sadece
dokuz otuz onbir arası ve Pazar günleri yapabilirsiniz demeliler; veya o
saatte başlamalısınız demeliler ki bizim sabahlarımızın ne olduğunu
hissedebilin. Bugün dengeli arama ağaçları hakkında konuşacağız. Bu
konuya bir süredir atıf yapıyorum. Bugünkü hedefimiz içinde yerleştirme,
silme yada arama yapabileceğimiz ve bunları log n süresi alan işlemlerle
gerçekleştirebileceğimiz bir arama ağacının veri yapısını oluşturmak
olacak. Yani öyle bir ağaç istiyoruz ki bunun yüksekliği mutlaka log n
olsun. Bu dengeli bir arama ağacının veri yapısıdır.
İstediğimiz veri yapısı öyle olsun ki
n sayıdaki elemandan oluşan
bir dinamik seti log n zamanında işleyebilsin. Yani söylediğimiz gibi bu
ağacın yüksekliği log n düzeyinde olsun. Şimdi daha dikkatli bakarsanız
aslında bir arama ağacı veri yapısını tanımlamadık; bir ikili arama
ağacının veri yapısını tanımladık ve bu o türlerden sadece biridir.
Bugün bunun üzerine odaklanacağız. Ve gelecek etütte de biz, daha
doğrusu siz ikili olmayan dengeli arama ağaçlarına bakacaksınız.
Her düğümün ya da dalın sabit sayıda ardılı yani çocuğu
olabilir; mutlaka iki olması şart değildir. Şimdi genelleme yaparak
tanımlama yapıyorum. Genel anlamda bir veri ağacını daha sonra
göreceksiniz. Bugün sadece ikili veri ağaçları üzerine odaklanacağız.
Şimdilik bunu tanımlamayacağım. Aslında birçok değişik dengeli arama
ağacı veri yapısı vardır. Şimdi söyleyeceklerim bunların arasında benim
bildiklerim. Bunların birincisi büyük harfle AVL ağaçları. Bu 1962 de
icat edilmişti ve bu hızlı veri yapılarının başlangıcını oluşturdu.
Bundan sonraki üç tanesi aslında aynı zamanda geliştiler ve bu haftaki
etütte bunları inceleyeceksiniz. Yani bunlar ikili olmayan ağaçlar.
İkili olanların yanı sıra ikili ve üçlü veya iki, üç ve dördüncü
dereceli ağaçlar vardır; ya da B genel kavram dereceli ağaçlar olur.
İki-üç ağaçları bulunan ikinci ağaçlardı ve 1970 de
Hopcroft tarafından icat edildiler. Bugün inceleyeceğimiz ağaçlara
kırmızı siyah ağaçlar denir. Bunlar garantili bir logaritmik yüksekliği
olan ikili arama ağaçlarıdır. Bunların dışında başkaları da var. Gelecek
hafta skip listleri yani atlama listelerini inceleyeceğiz; bunlar tam
anlamıyla ağaç değil ama ağaç benzeri şeylerdir.. Ve bu haftaki problem
setinizde inceleyeceğimiz treap’ler ama bunlarla ilgili fazla
konuşmayacağım.
Ama bunları elde etmek bir bakıma oldukça kolay çünkü
geçen hafta işlediğimiz konulara dayanıyorlar. Hatırlarsanız geçen hafta
eğer rastgele yapılanmış bir ikili arama ağacı oluşturursak bunun
beklenen zaman açısından yüksekliğinin log n olduğunu görmüştük.
Treap’ler de bunları dinamik yapmanın bir yoludur yani n sayıda elemanın
oluşturduğu statik bir set yerine, bu listelerde yerleştirme ve silme
yapabilirsiniz ve bunları verimli rastgele permütasyonlar kullanarak bir
ağacın içine yerleştirebilirsiniz. Yani bir bakıma bu en kolayıdır. Bu
aynı zamanda en yakın zamanda bulunun arama ağacı yapılarından biridir.
Bunu iki geometrici Rimon Sidell ve Aragen 1996 da icat ettiler. Yani
bunlar arama ağacı veri yapılarının sadece bir kaçı. Bu sınıfda
incelemeyeceğimiz tek tür AVL ağaçları olacaktır. Bunlar da çok zor
değildir; eğer ilginizi çekiyorsa kendiniz okuyabilirsiniz çünkü bunlar
eğlencelidir. Hatırladığım kadarıyla bunlarla ilgili kitapta da bir
problem var.
Ama bugün biz kırmızı siyah ağaçlara odaklanacağız ve bu
basit bir fikirdir. Belirli
bir yolla logaritmik yüksekliği garanti eder ve böylece tüm işlemler log
n süresinde desteklenir. Evet, bunlar
BST yani ikili arama
ağaçlarıdır; bunların her düğümünde bir parça ek bilgi vardır ve buna
renk alanı yani color field
denir. Bir renk alanı olan ağaca kırmızı siyah ağaç denebilmesi için
karşılaması gereken bazı özellikler vardır. Bunlara kırmızı siyah
özellikler adı verilir. Bunu yazmak biraz zaman alacak ama temelde
bayağı kolaydır. Onun için önce bunları yazacağım, ondan sonra bunların
ne anlama geldiğini açıklayacağım. Bunlarda dört özellik vardır.
Birincisi çok kolaydır. Her düğüm ya kırmızı ya da
siyahtır; böylece kırmızı siyah ağaç adı ortaya çıkar. Yani renk alanı
kırmızı veya siyah olduğunu belirten tek
bittir. Kırmızı düğümleri çift daire içine alarak belirteceğim
çünkü burada renkli tebeşirim yok ve siyah düğümleri de tek daire içine
alacağım. Büyük bir ihtimalle sizin de renkli kalemleriniz yoktur onun
için bu bizi bir dertten kurtaracak. Kırmızı çift daire; siyah ise tek
daire olacak.. Ve biz bazı açılardan siyah düğümleri tercih ederiz.
Kırmızı düğümler aslında bize bayağı sıkıntı yaratır ve bunu göreceğiz.
Evet, ikinci özellik kökün ve yaprakların hepsinin siyah
olmasıdır. Ve burada küçük bir numara yapacağım; ikili arama ağaçlarını
geçmişte yaptığımızdan biraz daha farklı işleyeceğim.
Normalde bir ağacı düşündüğünüzde aklınıza bir takım
düğümler gelir. Her düğümün ya 0, ya 1, ya da 2 çocuğu vardır ve şöyle
bir şeydir. Bir çocuğu olmayan her düğümün ardılları olduğunu hayal
edeceğim ve oralara birer nokta koyacağım; bunlar harici düğümler olacak
ve bunlara yaprak diyeceğim. Aslında normal olarak yapraklar şu
elemanlar olmalıydı. Ben burada her olmayan çocuk işaretleyicisi yerine
bir yaprak ekleyeceğim. Ve bunlar benim yapraklarım olacak. Bunlar
aslında o düğümlerden gelen NIL pointers yani 0 işaretleyicileridir.
Böylece her iç düğümün tam iki çocuğu olur ve her yaprağın sıfır çocuğu
olur. Söylemek istediğim bunlar siyah ve ikinci kuralıma göre bu da
siyah. Şimdi özellikler biraz daha ilginç hale geliyor. Her kırmızı
düğümün atası siyah olacak.
Yani ne zaman bir kırmızı düğümüm olursa bunun atası siyah
olmak zorunda; tek daire olmak zorunda. Böylece başka bir yaklaşımla bir
ağaçtaki herhangi bir yolla baktığınızda hiçbir zaman ardarda gelen iki
kırmızı düğüm göremeyeceksiniz. En çok kırmızı siyah kırmızı siyah
olabilir. Ardarda gelen siyah düğümler olabilir ama hiçbir zaman iki
kırmızı düğüm ardarda olmayacak. Şimdi son bir kuralımız daha var. Bu
kural bu yollarla ilgili birazcık daha açıklama getiriyor. Bu son kurala
göre tüm basit yollarda, yani düğümlerden sonra vertex yani uç
noktaların tekrarlanmadığı yollarda, x düğümünden
x’in ardıl yaprağına kadar olan
bütün yollarda mutlaka eşit sayıda siyah düğüm
vardır.
Şimdi bir şekil çizmek istiyorum. Elimizde bir ağaç var;
bu ağaçta bir x düğümü var. Bu x düğümünden aşağılarda olan tüm
yapraklara kadar bütün yollara bakıyorum. Bu yolların hepsinde eşit
sayıda siyah düğüm olmalı. Burada her birine dört tane siyah düğüm
çizeceğim; yaprağın kendisi ve üç tane de onun üstünde olacak.
Üçüncü özellikten biliyoruz ki bu düğümlerin en az yarısının kırmızı
olması gerekiyor, çünkü kırmızı düğüm durumunda onun atası mutlaka siyah
olmak zorundadır.
Ama ben bütün bu yollardaki siyah düğümlerin sayısının
birbiriyle aynı olmasını istiyorum. Şurada siyah yükseklik için yeterli
yer bırakmamışım; bu nedenle bunu şuraya yazacağım. Bu tüm yollar için
aynı olmak zorunda ama özellikle bu sayımı yaparken x’in kendisini
saymıyorum. Evet x siyahsa, buna siyah yükseklik diyorum, ve x’ in siyah
yüksekliği dört oluyor. Yani x kendisi de siyah olsa, siyah yüksekliği
yine de dört olacak. Burada bunlar algoritmaları daha açıklayıcı hale
getirmek için küçük detaylardı; şimdi bir kırmızı siyah ağaç örneğine
bakalım.
Size bir örnek göstereceğim ve bu özelliklerle neden
ilgilendiğimizi söyleyeceğim. Evet, bu ağacın bir takım özellikleri var.
Her şeyden önce bu bir ikili arama ağacı. Bunu sırasıyla geçiş ile
kontrol edebilirsiniz. Şu sayıları sıralı bir düzende size verecektir:
3, 7, 8, 10, 11, 18, 22 ve 26. Bu bir geçerli ikili arama ağacıdır.
Şimdilik bu yapraklara herhangi bir anahtar koymadan ekledik. Bunlar
şimdilik boşta duruyorlar. Şunlar sıfır işaretleyicileridir.
Yani şunların hepsine sıfır diyebilirsiniz. Herhangi bir ardıl
olmadığından bunları orada sadece işaretledik. Sonra da bazı düğümleri
çift daireyle işaretledim çünkü bunlar kırmızıya boyanacak. Eğer bunu
yapmasaydım o zaman siyah yükseklikler birbirlerine uyum göstermezdi. Bu
nedenle biraz dikkatli olmak zorundayım. Her düğümden aşağıdaki ardıl
bir yaprağa kadar olan siyah düğümlerin sayısını ölçmek istiyoruz.
Örneğin 0 işaretleyicilerin siyah yüksekliği 0’dır.
İyi, bu her zaman bir cevaptır. Yani bu elemanların siyah
yükseklikleri her zaman 0’dır. Bunu burada sadece belirteceğim. Bunların
siyah yükseklikleri 0’dır. Pekiyi, 3’ün siyah yüksekliği nedir? 0 mı?
Tam anlamı ile değil çünkü bu düğümler siyahtır.
Böylece siyah yüksekliği 1 olur. Burada (3) ü saymamakla haklısınız;
aslında o siyahtı ama sayılmaması gerekir. Sayımda bu hesaba katılmaz,
ama yapraklar katılır. Burada sadece iki yol var ve her ikisinde de aynı
sayıda siyah düğüm var ve zaten öyle de olması gerekir. Buraya bakacak
olursak, örneğin 8’e, bunun da siyah yüksekliği 1, ama kendisi kırmızı.
Tamam aynı şey 11 ve aynı şey 26 için geçerli. Bunların her birinin
sadece iki yolu var. Ve her yolda bir siyah düğüm var.
10; bunun siyah yüksekliği nedir? Hala 1’ dir, güzel çünkü
biz 10’un kendisini saymayız. Burada yapraklara dört tane yol var her
birinin içinde sadece 1 siyah düğüm var artı kök var ve bunu saymıyoruz.
22; aynı şeyin olmasını umuyoruz. Bu giderek daha ilginç hale geliyor.
Burada bir yol var ve onun üzerinde de bir siyah düğüm var. Burada daha
uzun olan başka yollar da var. Ama bunların üzerinde de sadece 1 siyah
düğüm var. Yani eğer kırmızı düğümleri görmezden gelecek olursanız bütün
yolların uzunluğu birbiriyle aynı. Tamam, şimdi 18, bunun daha büyük
olacağını umuyorum; burada siyah yükseklik 2 olmalı, çünkü bu yolların
her birinde bir siyah düğüm var ve yapraklar da da bir siyah düğüm var;
veya bir siyah düğüm burada ve bir siyah düğüm de
yapraklarda.
Ve son olarak da kökün siyah yüksekliğinin 2 olması
gerekiyor. Burada bunu görmek daha kolay tahmin ediyorum. Bu yolların
her biri 2 siyah düğüm içeriyor. Burada da aynı şey oluyor.
Evet, umarım bu özelliklerin bir anlamı olur. Bunların hepsini
kontrol etmedik. Her kırmızı düğümün bir siyah atası vardı. Bu yollara
şöyle bir bakarsak, bir kırmızı bir siyah olarak düzenlendiğini görürüz;
ya da sadece siyahlardan oluşan bir demet var. Ama hiçbir yolda iki
kırmızıyı arka arkaya koymuyoruz. Kök ve yapraklar siyah, çünkü biz bunu
tanım evresinde kabul ettik. Her düğüm, ya siyah ya da kırmızıdır; tamam
bu kolaydır. Bu belirli bir özellikler seti ama bu evrede biraz rastgele
gibi görünüyor. Bunun sonuçlarını gördüğümüz zaman daha fazla anlam
kazanacak.
Ama burada gerçekleştirmeye çalıştığımız bazı amaçlarımız
var. Bunlardan biri, bu özelliklerin ağacın logaritmik bir yüksekliği
olmasını sağlaması ve bunun da log n düzeyinde olmasıdır. Ve bu da
sağlanıyor fakat şu anda çok açık değil. Bu tüm özellikler bir araya
getirildiğinde ortaya çıkacak. 3 ve 4’ncü özellikler ana özelliklerdir.
Ama temelde bunların hepsine ihtiyacınız olur. Bu özelliklerden başka
bir beklentimiz de bunların bakımının bir şekilde kolay olması. Aslında
işin başında bu özelliği karşılayan bir ağaç yaratabilirim; örneğin
biraz dikkatli olmak kaydıyla, mükemmel dengeli bir ikili ağacı alıp
bütün düğümlerini siyah yaparsam,
bu özelliklerin hepsini karşılayacaktır. Ama bu kırmızı siyah bir
ağaçtır. İşin başında bu özellikleri sağlamak o kadar zor değildir;
şaşırtıcı olan bunların bakımı konusudur.
Bu ağaca bir düğüm eklemek ve bu ağaçtan bir düğüm
çıkarmak istediğimde bunun çok zor olmamasını istiyorum. log n süresinde
tüm bu özellikleri yeniden yapılanmasını istiyorum. Evet, bu aslında en
zor kısım olacak. İlk yapacağımız şey, bu özelliklerin ağacın
yüksekliğinin mutlaka log n düzeyinde olması gerektiğini ima ettiğini
kanıtlamak olacak. Böylece veri yapısındaki aramalar ve soruşturmalar
hızlı çalışacaktır. Burada zor olan şey bu özelliklerin ilk baştaki
özellikler değiştikten sonra da geçerli ve doğru olarak kalmasıdır.
Haydi kırmızı siyah bir ağacın yüksekliğine bir göz
atalım. Böylece bu özelliklerin nereden geldiğini ve bunları neden
seçtiğimizi anlamaya başlayacağız. Buradaki iddiam, n anahtarı olan
kırmızı siyah bir ağacın yüksekliğinin, (buradaki düğümleri hesaba
katmıyorum çünkü sadece iç düğümleri saymak istiyorum; buradaki ekstra
yapraklar ve eklediğim şeyleri de hesaba katmayacağım), en çok
(2 kere n log(n+1), yani (logaritma n) düzeyinde olacağıdır. Ama
burada iki düzeyiyle ifade edilen kesin bir sınırlama var. Bunun kanıtı
kitapta tümevarım yoluyla verilmiştir ve bunu okumanız gerekir.
Ben burada daha çok bu kanıtın ana hatlarını vereceğim.
Ama siz kesin kanıtı da, tümevarım yoluyla yapılan kanıtı da
okumalısınız, çünkü tümevarım yöntemi ile kanıtlamada pratik yapmak
iyidir. Buna karşılık
kanıtlama skeçi sizde daha çok sezgisel bir yaklaşım geliştirir ve
kırmızı siyah ağaçlarda ne olduğunu daha iyi anlarsınız ve gelecek etüde
de bir giriş yaparsınız; bu şimdiden söyleyeyim. Bu tahtayı boş
bırakacağım ve şuraya geçeceğim.
Şimdi yapacağım ilk iş bu ağaçta bazı değişiklikler
yaparak bizim tanıdığımız bir hale getirmek. İlk yapacağım ana şey de
her kırmızı düğümü, onun atasıyla birleştirmek olacak. Biliyoruz ki
kırmızı bir düğümün atası siyah olmak zorundadır. Böylece her kırmızı
düğümü, onun siyah atasıyla birleştireceğim. Şimdi şuradaki hale bir
bakalım. Şu kırmızı düğümü alacağım onun atasıyla birleştireceğim, bu
kırmızı düğümü alıp, onun yoluyla birleştireceğim ve böyle devam
edeceğim. Şu yukarıda ulaşamadığım bir tane var. Onun için buraya bu
şekli bir daha çizeceğim. Böylece 7 yani en üstteki düğüm şimdi 7/18
olacak. Bu ikisi birbiri ile birleşti fakat bunlardan başka birleşen
olmadı.
Sonra solda 3 var. Ona katılan olmadı ve normal olarak
birkaç yaprağı var. Şimdi bakarsanız, -- ama bunu bir kez daha
çizmeliyim. Şimdi bu düğümleri birleştiriyorum ve buradaki düğümlerin de
hepsini birleştiriyorum; çünkü bu kırmızı düğümlerin
her biri şu siyah düğüme
katılacak. Ve bu iki düğümü
de bir araya getiriyorum. Şu kırmızı düğümü
şu siyah düğümün içine koyuyorum.
Şimdi kök tarafından şöyle bir bakarsanız, bu 7/18 oldu.
Bundan üç çocuk yada ardıl sarkıyor. Bunu şu şekilde çizmek istiyorum
ama önce tahtayı aşağıya çekebilmem lazım. İyi, böylece 7 ile 18
arasında bu küme düğümü var; yani
8/10 ve 11’den oluşan bir birleşik düğüm var. Ve bu düğümden
de sarkan dört yaprak var. Ve sağ tarafta 18 den sonra 22/26 küme
düğümüm var ve bundan da sarkan 3 yaprak var. Evet, oldukça garip bir
ağaç oldu çünkü bugüne kadar hep ikili ağaçlarla uğraştık ama gelecek
derse bir ön hazırlık olarak bunu kabul edin. Bunun adı 2-3-4 ağacıdır.
Buna neden 2-3-4 ağacı denildiği konusunda tahmini olan var mı? Evet,
yaprakların dışında her düğümün 2, 3 veya 4 çocuğu ya da ardılı
olabilir. Sadece yaprakların çocuk sayısı 0’dır. 2-3-4 ağaçların daha
önce ima edilen hoş bir özelliği daha vardır. Aslında iki çocuğunun mu,
üç çocuğun mu, dört çocuğun mu olacağının gerçek bir kontrolü yoktur;
ama burada başka bir hoş özellik vardır. Evet? Bütün yapraklar aynı
derinliktedir, tamamıyla doğru. Ağaçtaki bütün bu elemanların
derinlikleri aynıdır; bu neden böyle olur? Dördüncü özellik nedeniyle..
Gelecek derste bu özelliğin nasıl muhafaza edileceğini
göreceksiniz. Ama bu transformasyon yada dönüşümden sonra bütün
yaprakların aynı derinlikte olduğu sonucu ortaya çıkar; çünkü bunların
derinlikleri veya diyelim ki ağaç içindeki yükseklikleri bunların siyah
yüksekliğidir. Ve bu yaprakların derinliği kökün de siyah yüksekliği
olacaktır. Kırmızı düğümlerin hepsini kaldırıyoruz ve dedik ki bir yola
baktığımızda ve kırmızı düğümleri ihmal ettiğimizde, o yol üzerindeki
siyah düğümlerin sayısı aynıdır. Şimdi temelde bütün siyah düğümleri
yerinde bırakıyoruz.
Ve böylece bütün bu yollardaki siyah düğümlerin sayısı
aynı olacaktır. Bu nedenle de her yaprak aynı derinlikte olacaktır. Bu
özelliklerin bir kısmını yazayım:
Her iç düğümün 2
ile 4 arasında ardılı olur ve her yaprak aynı derinliğe sahip olur, ve
bu kökün siyah yüksekliğine eşittir. Bu 4’üncü özellikten kaynaklanır.
Tamam, şimdi bu bize bir sürü şey anlatıyor. Aslında bu dönüşüm, temelde
kırmızı düğümleri görmezden geliyor. Böylece sadece siyah düğümlere
odaklandığınızda yükseklik, siyah yükseklik oluyor. Siyah yükseklik de
bize kökle yapraklar arasındaki tüm yolların aynı uzunlukta olduğunu
söylüyor. Bu nedenle tüm bu düğümler aynı düzeydedir. Yaprakların aynı
düzeyde olması iyi bir şeydir, çünkü bu ağacınızın oldukça dengeli
olduğu anlamına gelir. Eğer bir ağacınız varsa ve bütün düğümlerden
dallanmalar oluyorsa ve bunların da en azından iki çocuğu varsa ve tüm
yapraklar da aynı düzeyde ise o zaman bu ağaç oldukça dengeli bir
durumdur. Tamam, şimdi bunun bir formunu kanıtlayacağız. Bu ağacın
yüksekliğine h’ diyeceğim. Orijinal ağacın yüksekliği h idi. Burada
sınırlamak istediğimiz de buydu. Bu nedenle yapılacak ilk şey h’ nü
sınırlamaktır. Sonra da h ile h’ arasında bir ilişki kuracağız.
Tamam, ilk soru bu ağaçta kaç tane yaprağım olacağı
olduğudur? Ve hangi ağaca baktığım da farketmez çünkü yaprak sayısıyla
ilgili herhangi bir değişiklik yapmadım. Bütün yapraklar siyahtır. Bu
nedenle yapraklar hiç değişmedi. Şu ağaçta, dolayısıyla bu ağaçta kaç
tane yaprak vardır? Afedersiniz? 9, evet doğru 9 tane var ama ben daha
genel sordum, kusura bakmayın. Bu örnekte 9 tane var. Kaç tane anahtar
var? 8, bu durumda genelde 9’u 8’in bir fonksiyonu olarak nasıl
yazarsınız? 9’un veya 8’in büyük değerleri için.. Afedersiniz? Artı 1,
güzel, doğru cevap tahminle geldi n+1. Pekiyi, neden n+1?
Şuradaki ikili ağaç durumuna bakarak neler olup bittiğini
anlamaya çalışalım. Ne zaman bir anahtarınız varsa orada iki tane dal
oluyor. Ve bu çok iyi bir kanıt değil. Burada dallanan ikili ağaç
dediğimiz bir yapı var. Her iç düğümün en
az iki çocuğu yani ardılı var. Ve biz yaprak sayısını, işleme alınan iç
düğümlerin sayısı cinsinden hesaplıyoruz. Bir ağaçtaki yaprakların
sayısı, yani dallanan bir ağaçtaki yaprakların sayısı her zaman iç
düğümlerin sayısı artı 1.
Bunu bilmeniz gerekir. Bunu tümevarımla
kanıtlayabilirsiniz. Evet, yaprakların sayısı n+1’dir Eğer tek çocuğunuz
varsa bu geçerli olmaz. Bunun geçerli olması için her iç düğümün
dallanma faktörünün 2 olması gerekir. Evet bu bir either ağacıdır yani
ne de ağacıdır ve şimdi de yaprakların sayısı ile ağacın
yüksekliği arasında bir ilişki çıkarmak istiyoruz. Evet, burada
kullanabileceğimiz iyi bir ilişki ne olabilir? Kaç yaprak olduğunu
kesinlikle biliyoruz ve bu bir şekilde bizi n ile ilişkilendirecektir.
Bizi ilgilendiren yüksekliktir ve bu ağacın yüksekliğine bakalım. Şimdi
elimde bir 2-3-4 ağacı varsa ve bunun yüksekliği h’ ise, bunun kaç
yaprağı olabilir? Buradaki en çok ve en az yaprak sayısı ne olacaktır? 2
üzeri h den 4 üzeri h kuvvetine. yada h’ kuvvetine kadar..
Böylece 2-3-4 ağacındaki yaprakların sayısının en fazla 4’
ün h’ kuvvetine kadar gideceğini biliriz; çünkü bir düğümden en fazla 4
dal ayrılabilir. Ve ayrıca yaprakların sayısının en az 2’nin h’
kuvvetine kadar olacağını biliyoruz; çünkü her düğümde en az 2 dallanma
olabilir. İşte anahtar budur. Bunlardan sadece biri ile ilgileniyorum, o
da şu. Yani 2’nin h’ kuvveti en çok n+1’e eşit olabilir. Yani buradaki
yaprakların sayısı n+1’dir. Bunu kesinlikle biliyoruz. Bu nedenle bunu
yeniden yazarız ve her iki tarafta da logaritma alırız. Bu durumda h’ en
çok n+1’in logaritması olabilir. Böylece hoş, dengeli bir ağaç elde
ederiz. Bu yeterince sezgisel olmalı. Eğer her düğümden iki dal çıksaydı
ve bütün yapraklar da aynı düzeyde olsaydı bu mükemmel bir ağaç olurdu.
Bu durumda da bunun yüksekliği logaritma 2 tabanında n+1 olurdu; tam
anlamı ile n olmazdı.
Bu ağacın yüksekliği olmalıdır. Burada daha fazla dallanma
olabilirdi ve bu şekli bir bakıma daha da sığlaştırabilirdi. Yani aynı
yükseklikte daha fazla yaprağım olabilirdi. Ama bu, sadece benim için
iyidir. Bu yüksekliği yaprakların sayısı bazında azaltır. Burada n+1
yaprakların sayısı idi. Bu hoş oldu, ağacın yüksekliği ile ilgili kolay
bir üst sınır elde edildi. Aslında bizim ilgi alanımız şu ağacın
yüksekliğidir; bu nedenle h’yü h’ ile ilişkilendirmek istiyoruz.
Bunu nasıl yapabileceğimizle ilgili herhangi bir öneri var
mı? Bu indirgenmiş ağacın yüksekliğinin şundan çok da fazla küçük
olmayacağını nasıl biliriz? Bunun en fazla log n olduğunu biliyoruz.
Bunun da en çok 2 log n+1 olmasını istiyoruz; yani yanıtı biliyoruz.
Teoremi söylemiştik. Afedersiniz? Doğru üçüncü özellik bize her siyah
düğüm için sadece bir kırmızı düğümümüz olabileceğini söylüyordu. Bu
durumda en fazla kırmızıyla siyahı birbiriyle değiştirebiliriz.
Eğer kökten bir yaprağa kadar giden bu yollara bakarsak,
burada olabilecek kırmızı düğümlerin sayısı en çok o yolun yarı uzunluğu
kadar olacaktır. Ve biz tüm yolların en büyük değerini alırsak bu ağacın
yüksekliğini verecektir. Yani h’nin en çok 2 çarpı h’ olduğunu
biliriz. Başka bir deyişle, h üssünü en az h nin yarısı olacak şekilde
düşünmek kolaylık getirir. Çünkü, bunu doğru yaptığımı varsayarsam, her
kök-yaprak hattında en fazla düğümlerin yarısı kırmızı olabilir.
Yani en azından yarısı siyah olmak zorundadır. Ve bütün
siyah düğümler bu şekilde gösterilmiş olduğundan, elimizde şu bağıntı
olabiliyor: h en çok 2 kere log(n+1)’dir. Tamam, bu oldukça kolaydı. Ama
unutmamanız gereken bir şey var; bu ağacın dengeli olması lazım ve bu
ikisi birbirinden çok farklı değil. Gelecek etütte bu formdaki ağaçlarla
nasıl işlem yapacağınızı göreceksiniz. Bunu yapmanın akıllıca bir yolu
var. Bunlar 2-3-4 ağaçları. Bugün biz sadece kırmızı siyah formdaki
ağaçlarla işlem yapacağız. Ve bugünkü derste göreceklerinizle gelecek
etütte göreceğiniz işlemler aslında ilk bakışta birbirinden ilgisiz gibi
görünecek..
Ama aslında birbirleriyle aynıdırlar; sadece benzerlik
biraz gizlidir. Evet, iyi haber buydu. Şimdi biliyoruz ki bütün kırmızı
siyah ağaçlar dengeli. Yani, eğer ağacımızın kırmızı siyah bir ağaç
olarak kaldığından eminsek, o zaman her şey yolunda demektir. Burada her
şeyin yolunda olmasını ağacın yüksekliğinin her zaman log n olarak
kalması şeklinde yorumluyorum. Kırmızı siyah bir ağaçta sorgulama
yaptığımda ki sorgulamalar arama, belirli bir anahtarı bulma, en küçük
değeri bulma, en büyük değeri bulma, bir ardılı bulma, ya da bir atayı
bulmak şeklinde yorumlanabilir ve bu sorgulamaları biz ikili arama
ağacında görmüştük.
Ve bunları n düzeyindeki yükseklik süresinde nasıl ele
alacağımızı biliyoruz. Buradaki yükseklik de log n, onun için bir
kırmızı siyah ağaçtaki işlemler de log n düzeyinde zaman alacaktır. Yani
sorgulamalar oldukça kolay.
Sorgulamalarla ilgili bize avantaj sağlayan buradaki
dengedir ve bu bir sürpriz değildir; biliyoruz ki denge olması iyi bir
şeydir. Zor olan şey güncellemeleri yapmak olacak. Ve buradaki bağlamda
güncelleme, araya sokma ve silme demektir. Genellikle veri yapılarında
biz sorgulama deyince bu veri yapısındaki bazı soruları sormak ondan
sonra da yapının içindeki veriyi değiştirmeyi kast ederiz. Ve çoğu zaman
biz bu işi yaparken dinamik setleri düşünürüz. Dinamik setleri bir
elemanı eklemek ya da çıkarmak şeklinde değiştirebilirsiniz. Burada her
türlü soruyu da sorabilirsiniz. Öncelikli kuyruklarda başka türlü
güncellemeler, örneğin en küçüğü sil tipi güncellemeler de olabilir.
Burada biz minimumu bulduk, sonra bunu silebiliriz. Tipik
olarak bu işlemler bizi ilgilendiren işlemlerdir. Ve bunun gibi
işlemleri yapmakla, güncellemeler ve sorgulamalarla ilgili konuşacağız;
ilgili konu ne ise bunları konuşacağız. Problem setlerinde
destekleyebileceğiniz çeşitli sorgulamalar göreceksiniz.
Tamam, biz güncellemeleri nasıl destekleyebiliriz?
Elimizde ikili arama ağacı araya yerleştirmeleri vardı ve bunlara ağaç
araya yerleştirmesi diyoruz.
İkili arama ağacı silmeleri var ve bunlara da ağaç
silmeleri diyoruz. Bunlar ikili arama ağacının özelliklerini korur ama
her zaman dengeyi koruyabildiklerini söyleyemeyiz. Birkaç tane düğümü
araya yerleştirebiliriz. Yeni minimum elemanlar eklemeyi sürdürürsek,
işin sonunda gerçekten bir uzun yol elde ederiz. Bu açıdan bakarsak bu
uygulamalar kırmızı siyah özellikleri korumazlar çünkü biz başında
kırmızı siyahın dengeyi ima ettiğini biliyoruz. Özellikle de biraz önce
sildiğim birinci özelliği karşılamazlar ki bu da her düğümün
ya kırmızı ya da siyah
olacağıydı. Bu uygulamada bir düğüm ekleyebilirsiniz ama ona bir renk
vermezsiniz. Bu nedenle ek olarak buna bir de renk atamamız gerekir. Ve
bunu yaptığımız anda da büyük bir olasılıkla başka bir özelliği
karşılamaz duruma geleceğiz. Ondan sonra da bu özelliği tekrar düzeltmek
zorunda kalacağız ve bu iş böyle gidecek. Bu nedenle bu biraz karmaşık
ama bununla uğraştığımız zaman o kadar zor olmadığını göreceksiniz.
Yani, güncellemeler ağacın yapısını değiştirmelidir. Ve
ağacın kırmızı siyah özelliklerini korumak için üç türde değişiklik
yapmaya ihtiyaç vardır. İlk yapılacak şey aslında BST işlemidir yani
ağaç araya yerleştirme veya ağaç silme işlemidir. Bunun nasıl
yapılacağını biliyoruz. Şimdi bunu yapalım. Bunu yaparken bazı
düğümlerin renklerini değiştirmek zorunda kalacağız. Özellikle de araya
yerleştireceğimizin mutlaka bir rengi olması gerekir. Ve genellikle bir
düğümü oradan çıkarırsak bunu ve onunla birlikte komşu düğümleri de
yeniden renklendirmemiz gerekir.
Yapacağımız bir başka tür işlem daha var. Ttekrar
renklendirmek bunu kırmızı ya da siyah yapmak demektir. Yapılacak diğer
işlem ağacın yapısını tekrar düzenlemektir; yani buradaki işaretçileri
bir düğümden diğerine olan linkleri değiştirmektir. Ve bunu da çok
dikkatle yapılandırılmış bir şekilde yapacağız. Bu nedenle de kırmızı
siyah ağaçlar çok ilginçtir. Bunlarda yapılan değişiklikler oldukça
basittir ve çok da fazla değildir. Bunlara
rotasyonlar denir. İşte
burada bir rotasyon var.
Bu ağacın cinsine özgü yani jenerik bir kısmının
çizimidir. Elimizde iki tane düğüm var, A ve B.
Buradan sarkan bazı alt ağaçlar var ve bunları üçgenler şeklinde çizdik.
Bunların hangi büyüklükte olduğunu bilmiyoruz. Ama bilmemiz gereken şey
bunların hepsinin aynı siyah yükseklikte olduğu; böylece bu ağaç bir
kırmızı siyah ağaç olur. Ama genelde böyle bir şey görünür. Burada bir
ata ve ağacın içinde çizmediğimiz diğer bölümler vardır. Bu alt ağaçlara
Yunanca isimler vereceğim; alfa, beta ve gamma diyeceğim. Ve ben B’nin
sağa rotasyonunu yani sağa dönmesini tanımlayacağım. Genelde eğer bir B
düğümüm varsa, buna bakıp bunda bir sağa rotasyon yapacaksam, bu çizimde
solunda görünen ardılına ve iki düğümün alt ağaçlarına
bakıp bu resmi çizerim.
Ve şu ağacı oluştururum. Yani tüm yaptığım bu kenarı
doksan derece döndürmekti. Eskiden B’nin atası şimdi A’nın atası oldu. A
şimdi B’nin yeni atasıdır; bu durumda alt ağaçlar tekrar organize olur.
Daha önce şu ikisi A’nın alt ağaçlarıydı. Ve gamma B’nin bir alt
ağacıydı. Gamma hala B’nin bir alt ağacı ve alfa da hala A’nın bir alt
ağacı. Ama beta B’nin alt ağacı oldu. Burada kontrol etmemiz gereken ana
husus bu işlemin ikili arama ağacı özelliğini muhafaza etmesidir.
Hatırlarsanız, ikili arama ağacının özellikleri çerçevesinde, sol alt
ağaçtaki elemanların hepsi bu düğümdeki değere eşit ya da ondan daha
küçük ve sağ alt ağaçtaki elemanların hepsi de bu düğüm elemanının
değerinden daha büyük veya ona eşit olarak belirtilmişti.
Böylece özellikle herhangi bir düğümü
ele aldığımızda, örneğin alfadaki
küçük a, betadaki küçük b ve gammadaki küçük c’ ye baktığımızda, a büyük
A’ya eşit ya da ondan küçük; küçük b’ye eşit yada ondan küçük;, büyük
B’ye eşit yada ondan küçük; küçük c’ye eşit yada ondan küçüktür. Ve bu
durum hem sol tarafta hem de sağ taraftaki kuraldır; çünkü alfa her
şeyin solundadır. Beta A ile B arasındadır ve gamma B’den sonra gelir.
Burada da aynı şey geçerlidir. Beta hala büyük A ve büyük
B arasındaki bütün düğümleri kapsar.
Ve bu iyidir. Bu işlemi kesinlikle kullanabiliriz ve sonunda hala ikili
arama ağaçları bozulmaz ve burada rotasyonları çok dikkatli bir şekilde
kullanarak bütün bu özelliklerin yok olmamasını sağlarız. İşin zor
kısımı da budur. Ama rotasyonlar bizim anahtarlarımız olacak. Burada
yaptığımız sağa dönme işlemi yada rotasyonuydu.
Bunun tersi sola dönme işlemidir. Şu büyük A’nın sola
dönmesidir. Genelde işleme alınan iki düğüm arasında üsttekini
listeleriz. Yani B’nin sağa rotasyonu size bunu verir. A’nın sola
rotasyonu da size bunu verecektir. Bunlar tersinebilir işlemlerdir ve bu
da iyi görünüyor. Bir başka açıdan bunlar sabit zaman alan işlemlerdir
-- çünkü burada sabit sayıda işaretçiyi değiştiriyoruz.
B düğümünü bildiğiniz sürece bunun beta olmasını hala
istiyorsanız ve bununla ilgileniyorsanız soldaki işaretçiyi B’nin soluna
A’nın sağına gelecek şekilde yerleştirirsiniz ve bu işlem böyle devam
eder. Bu değişikliklerden sabit sayıda yaparsınız. Bu arada ataları da
güncellersiniz. Burada değiştirdiğiniz linklerin sayısı sabittir, bu
nedenle yapacağınız işlem sayısı da sabittir. Belki bu rotasyonları ya
da dönme işlemlerini daha önce görmüşsünüzdür. Ama biz bunları karmaşık
bir yolla kullanacağız.
Şimdi araya yerleştirmeyi nasıl yapacağımıza bir bakalım.
Bir bakıma bunu üç kez göreceğiz. Önce size temeldeki düşünceyi
anlatayım ve bu oldukça kolay. Bunun bir kısmını daha önce belirtmiştim.
Sonra bu konuda bir örnek yapacağız ki bunu iyice hazmedebilin ve ondan
sonra da bunun sözde kodunu size vereceğim ve eve gittiğinizde
isterseniz onu uygulayabilirsiniz. Tamam, şimdi buna kırmızı siyah araya
yerleştirme diyorum; kitapta buna RB araya yerleştirmesi deniliyor; bu
RB root birasının kısaltılmışı değil, kırmızı siyahın kısaltılması
olarak algılanmalı.
Tamam, şimdi yapacağımız ilk şey daha önce söylediğim gibi
ikili arama ağacı mantığında şu düğümü araya yerleştirmek. Bu durumda x
bir yaprak olur. Biz x’in gitmesi gerektiği yer konusunda bir arama
yaptık. Buna bir yaprak dememeliyim. Şu anda sarkan bir -. Bu bir iç
düğüm ve orijinal düğümlerden birinden sarkıyor. Belki bunu tam şuraya
ekledik. Bu durumda ondan sarkan iki tane yeni yaprak olur. İç ardılları
yok. Ve bunun için bir renk seçmeliyiz. Ve bu rengi de kırmızı olarak
seçeceğiz.
Pekiyi neden kırmızı seçtik? Çünkü iki renkten birini
seçmek zorundayız. Burada yazı tura atabiliriz. Bu sonuç verebilir ama
bizim işimizi daha karmaşık hale getirir. Evet, buraya yeni bir düğüm
ekliyoruz. Bu bir kök ya da yaprak olmak zorunda değil, bu nedenle
ikinci özellik nedeni ile siyah olması da şart değil. Üçüncü özelliğe
göre her kırmızı düğümün bir siyah atası olmak zorunda. Bu bir problem
olabilir. Problem eğer atası kırmızıysa oluşur. O zaman ikinci
afedersiniz üçüncü özelliğe aykırı düşmüş oluruz. Ama iyi haber dördüncü
özelliğin hala karşılanması, çünkü dördüncü özellik sadece değişik
yollardaki siyahları sayar. Bu aslında karşılanması bayağı zor bir
özelliktir. Bu nedenle eğer kırmızı bir düğüm eklersek siyah
yüksekliklerin hiç birisi değişmeyecektir.
Yoldaki siyah düğümlerin sayısı hiçbir şekilde değişmiyor. Ve bunun da
geçerli olması lazımdır. Burada karşılayamadığımız tek özellik
üçüncü özellik olabilir. Ve bu kabullenilebilir. İşin başında bir
şeyleri bozacağımızı biliyorduk. Sadece bir ikili ağaç araya
yerleştirmesi yapıp kurtulamazdık. Tabii şimdi bu ağaçta bunu bir
deneyelim. Yani bunu düzeltmeyi deneyelim.
Üçüncü özelliği nasıl düzeltiriz? Üçüncü özellikteki ihlali ağaç boyunca
yukarıya doğru taşırız. Yani x düğümünde başlar bunu yukarıda köke doğru
taşırız. Bunu yeniden renklendirmeyle yaparız. Önce yeniden renklendirme
yapacağız ve bir noktaya geldiğimizde ihlali rotasyon kullanarak
düzelteceğiz; belki de yeniden renklendirme yapmamız gerekecek.
Şimdi bu algoritmayı uygulamada görelim. Ben bu ağacı buraya
kopyalayacağım ve sizin de kopyalamanız gerekecek. Yani ilk şeklin
üzerinde değişiklikler yapmak yerine bunu yeniden çizeceğim. Şimdi bu
güzel kırmızı siyah ağacı oluşturduk ve araya yeni bir 15 değeri
yerleştireceğiz. 22 siyah ve 22 yeni siyah olacak. Aslında bu ağacın
eskisiyle aynı olması gerekiyor. Şimdi araya yerleştirmek için seçtiğim
sayı 15 çünkü bu oldukça ilginç bir araya yerleştirme durumu ortaya
çıkaracak.
Bazen araya yerleştirmeler çok iş gerektirmez. Rotasyonu yaparız ve
işimiz biter. Ama burada ilginç bir duruma bakmak istiyorum. Bu nedenle
15’i araya yerleştiriyorum. 15; 7’den
büyük. 18’den de küçük. 10’dan büyük. 11’den büyük. Bu nedenle 15 buraya
gelir. Bu nedenle buraya yeni bir kırmızı düğüm, 15 düğümunu ekliyoruz.
Bu durumda bundan sarkan iki tane siyah yaprak var ve bir tane siyah
yaprağın yerine geçti. Bu durumda üçüncü özelliği ihlal ettik çünkü
kırmızı bir düğüme yeni bir kırmızı ardıl ekledik.
Bu durumda elimizde kökten yaprağa giden hatta arka arkaya iki tane
kırmızı düğüm oldu. Şimdi bunu siyah yapmak isteriz ama bu siyah
yüksekliklerin düzenini tamamen bozar çünkü bu düğümün bu yolda bir
siyah düğümü, ve bu yolun üzerinde aşağıya doğru iki tane siyah düğümü
olur. Ve bu iyi değil. Ne yapabiliriz? Önce yeniden renklendirmeyi
deneyelim. Evet bunu hatırlamak her zaman biraz zaman alır.
Evet bizim buradaki düzeltmemiz yeniden renklendirme olacak. Benim
aklıma gelen ve doğru olmayan ilk şey yeniden renklendirmeyi buralarda
yapmaktı. Ama bu çok iyi görünmüyor, çünkü buralarda bazı kırmızılarımız
var ve şurada da bir siyah düğümümüz var. Bu nedenle bunu kırmızı şunu
da siyah yapamayız. İyi çalışmaz böyle bir şey. Şimdi daha yukarıya
15’in büyük atasına bakacak olursak burada bir siyah düğüm ve şurada da
iki tane kırmızı ardıl var.
Bu aslında iyi bir haber çünkü bu durumda şunları iki siyah ardıl ve bir
kırmızı ata haline getirebiliriz. Yerel olarak bu oldukça uygun olacak.
Bu uygulama aslında siyah yüksekliğini değiştirmeyecek çünkü bu
düğümlerden geçecek herhangi bir yol aynı sayıda siyah düğümlerden
geçecektir. Yani buradaki siyah düğümden geçmek yerine ya şuradaki siyah
düğümden veya buradaki siyah düğümden geçecek,
çünkü yollar her zaman yapraklara doğru gider.
Evet yapacağımız şey bu bunların rengini değiştirmek olacak. Ve bu
durumda kırmızı olan 10’u elde edeceğiz, sonra 8 siyah ve 11
siyah olacak ve bunlar değişmeyecek. Diğerlerinin hiç birisi
değişmeyecek. Bu durumda 15’i kırmızı bırakacağız; artık ihlal ortadan
kalktı. 15 uygun oldu, çünkü bu durumda atası siyah oldu. Şimdi, yeni
bir ihlalimiz oluştu; burada 18 var ve 18 kırmızı. Ve elimizde kalan tek
ihlal de bu. Genelde bunu yaparken sadece bir ihlal olur ve onu
düzeltene kadar da bu devam eder. Sonunda da sıfır ihlal elde ederiz.
Şimdi 10 ile 18 arasında bir ihlal var. Bu bana her zaman sezgiyle
anlaşılması zor gelmiştir.
Şimdi şu kopya kâğıdıma bir daha bakayım. Gerçekten mi? Hayır değil.
Diyecektim ki biz artık yeniden renklendirme yapamayız. İyi o kadar da
kötü değilim. Şimdi yapacağımız şey tekrar 10’un büyük atasına bakmaktır
ki bu da 7 ve ağacın köküdür. Bu siyah ama ardıllarından biri siyah
diğeri kırmızı. Bu nedenle aynı oyunu burada oynayıp 7’nin siyahlığını
kaldırıp bunu altındaki iki ardıla aktaramayız.
Kökün siyah olarak kalması konusunu şimdilik unutun. Bu özelliği
şimdilik görmezden geleceğiz. Bu ikisini siyah yapıp şunu kırmızıya
çeviremiyoruz çünkü bu durumda bir dengesizlik ortaya çıkıyor. Bu zaten
siyah. Böyle bir durumda buradan aşağıya giden yollarda şu yolu takip
eden duruma göre bir eksik siyah düğüm olur. Yani 7’yi veya onun
ardıllarını yeniden renklendiremeyiz. Bu durumda bir rotasyon yapmamız
gerekir. Ve bunu da sona doğru yapmamızda yarar var. Bu nedenle
rotasyonu şu kenarda yapacağım. 18’i sağa doğru döndüreceğim.
Bundan sonraki işlem ne olur? 18’in sağa dönmesi. Bundan sonra bir işlem
daha yapacağız. Önce 18’i sağa çevirelim. Kök olduğu gibi kalır; yani 7,
3 ve onun çocukları. 7’nin sağ ardılı artık 18 değil. Şimdi bu değer 10
oldu 18 de 10’un kırmızı ardılı oldu. Evet, burada 8 ve onun iki ardılı
var. 11 ve 15; bu alt ağaç 10 ile 18 arasına sığar. Şöyle olur: 11 ve
15. Sonra da sağdaki alt ağaç var. 18’in sağında olan her şey şuraya
girer: 22 ve 26. Ve umuyorum ki bu işlemler sırasında herhangi bir renk
değiştirmiyorum. Eğer yaptıysam lütfen beni uyarın.
Evet, iyi görünüyor. Ama hala bu
ihlal ve 10 ile 18 arasında sorun var. Ama bunu daha düzgün hale
getirdim. Evet yapmak istediğimiz şey buydu; 18 ile ihlali yaratan onun
büyük atası arasındaki bağlantıyı doğrusal bir bağlantı haline getirmek:
iki sağ ve iki sol. Burada solda bir sağ sol zikzağı vardı ve bunu düz
hale getirmek istedik. Sonunda baktığımızda şundan daha dengeli bir ağaç
gibi görünmüyor. Aslında biraz daha kötü gibi görünüyor.
Şimdi yapabileceğimiz şey şunları döndürmek, ya da daha doğrusu şu
kenarı döndürmek olabilir. Bu durumda 7’yi sola döndüreceğim 10’u kök
yapacağım ve ondan sonra durum daha dengeli görünecek. Bu 7’nin sola
rotasyonudur. Bu evrede bir de yeniden renklendirme yapacağım, çünkü bir
şekil daha çizmek istemiyorum ve kök siyah olmak zorundaydı. Bu nedenle
10’u hemen siyaha çevireceğim. Ve 7’yi kırmızı yapacağım. İşte
değişiklik bu. Ve geri kalanı sadece rotasyon olacak. Şimdi 18 şurada
olacak. Buna göre burada da bir rotasyon yapmam lazım çünkü kırmızı
siyahlık olgusuna dikkat etmem gerekiyor.
8, 7 ile 10 arasındadır; onun için buraya gider. 11, 10 ile 18 arasına
gireceğinden şuraya gider. 22 ve 26 18’den sonra gelir. Ve eğer
şanslıysam istediğim bütün özellikleri karşılamış olurum. Her düğüm ya
kırmızı ya siyah. Her siyah düğümün bir ardılı var. Bu en son değişim
yaptığımız yer. Kırmızı düğümlerin siyah ardılları olması gerekiyor ve
bütün siyah yüksekliklerin iyi tanımlanmış olması gerekiyor. Her
düğümden yaprağa kadar olan yolda siyah
düğümlerin sayısının aynı olması
gerekiyor. Ve bunu kontrol ettiğinizde,ki daha önceden doğruydu, burada
yeniden renklendirmeyle biraz kurnazlık yaptım ama hala doğrudur.
Yani bunu sadece bu rotasyonun etrafında yerel olarak da kontrol
edebilirsiniz. Bunu birazdan yapacağız. Şimdilik şu örnek üzerinde
çalışalım. Bu yeniden renklendirme ve rotasyonların nereden geldiği o
kadar açık olmayabilir ama gördüğünüz gibi çalıştı ve en azından sizi
bunun mümkün olabileceği konusunda ikna etti. Şimdi bunu yapmak için
genel bir algoritma vereceğiz. Devam etmeden önce sorular var mı? Yani
demek istiyorum ki algoritmayı sadece yazmak yeterince sezgisel olmuyor.
Kırmızı siyah ağaçlar sizin biraz oynayabileceğiniz şeylerdir. Dersiniz
ki sadece yeniden renklendirme ve rotasyonlarla ilgileneceğim. Kendimi
bu işlemlerle sınırlayacağım. Ne yapabilirim? Önce yeniden
renklendirmeyi denerim eğer bu çalışırsa o zaman problemi daha yüksek
düzeye taşır. Ve burada sadece log n düzeyleri vardır; yani sonunda bu
işlem log n düzeyinde zaman alır. Belli bir noktada tıkanırım. Artık
yeniden renklendirme yapamam. Bu durumda da birkaç tane rotasyon işi
görecektir.
Her zaman iki rotasyon yeterli olacaktır. Siz bunlarla birazcık
oynarsanız sonunda
işlediğini görürsünüz Ve nasılını burada açıklayacağım. Varsayalım ki
elimizde bir kırmızı siyah ağaç var ve x değerini
araya yerleştirmek istiyoruz. Algoritması burada. Önce bunu
BST yani ikili arama ağacında araya yerleştireceğiz; bildiğimiz
bir şey olduğu için. Sonra bu düğümü kırmızıya boyayacağız. Şimdi burada
biraz daha kesin bir simgelem kullanacağım. Renk x’in bir alanı olacak.
Ve sonra bir “while”
döngüsüyle ağaç içerisinde yukarıya doğru köke ya da siyah bir düğüme
gelene kadar yürüyeceğiz. Yani
genelde x başta bizim araya yerleştireceğimiz eleman olacak; ama sonra
ağacın içerisinde yukarıya doğru yürüyeceğiz
.
Eğer x’in bir siyah düğüm olduğunu görürsek bundan mutlu olacağız çünkü
belki bunun atası kırmızıdır. Belki de değildir. Ama bu beni
ilgilendirmiyor. Siyah düğümlerin rastgele renkli ataları olabilir.
Bizim dert edindiğimiz kırmızı düğümler. Eğer x kırmızıysa bu döngüye
devam etmeniz gerekir. Tabii bu arada yanlış bir şey yazdım. Eğer
rengimiz kırmızıysa bunu yapmaya devam edeceğiz. Böylece ortada 3 durum
olur; nasıl saydığınıza bağlı olarak 6 durum da olabilir. Bu nedenle
bunu ezberlemek biraz karışıktır. Ama ortada bazı simetrik durumlar da
var. Bunları şimdi çizeyim. Bizim ilgi alanımız daha önce söylediğim
gibi x ile onun büyük atası bölgesindedir.
Burada kısa olması nedeniyle p[x]i kullanıyorum ve bu da x’in atası
anlamına gelecek. Yani p[p[x]], x’in büyük atasıdır. p[p[x]]’in
solundaki sol ardıldır. Burada x ile ilgilendiğim için ona bakarım ve
herhangi bir yön tayin etmem. x, p[x]’in
bir ardılıdır ve p[x] de daha öncekinin yani p[p[ x]]’in ardılıdır.
Şimdi bu kenarlar dikey değildir; ya sola ya da sağa eğimlidirler. Ve
ben hangisi ile ilgileneceğim? Burada bakmam gereken atanın büyük atanın
sol ardılı olup olmadığı. Yani bilmek istediğim, bunun gibi mi
görüneceğidir.
Bu evrede x’in atasının solunda mı sağında mı olduğunu bilmiyorum, ama
x’in atası p[px]]’in sol ardılı mıdır, yoksa sağ ardılı mıdır? Ve bu iki
durum birbirine tamamen simetriktir. Ama bunu bir şekilde varsaymam
gerekiyor, aksi takdirde bu resimleri çizemem. Tamam, şimdi bu durumda
şuna kategori A diyelim. Ve bu da kategori B olsun . Ve size kategori
A‘da ne yapılacağını söyleyeceğim. Ve kategori B de simetrik olacak.
Yani sol ile sağ arasında gidip gelebilirsiniz. Tamam, şimdi bu A.
Kategori A’nın içinde 3 tane durum oluşur. Kategori B’nin içinde de
benzer ama tersinden 3 durum oluşur.
Bu durumda büyük atanın diğer çocuklarına bakacağız. Bu hangi yöne
baktığımızı neden bilmemiz gerektiğine bir açıklık getirir. Eğer x’in
atası büyük atanın solunda kalıyorsa, o zaman büyük atanın öteki
ardılına yani büyük atanın sağında kalan ardıla bakmamız gerekiyor ve
buna y düğümü diyelim. Bunun başka bir ismi, y’nin erkek ya da dişi
olmasına bağlı olarak, x’in amcası ya da halasıdır. Evet, bu amca ya da
hala. Maalesef İngilizcede bunun cinsiyete bağlı olmayan benim bildiğim
kadarıyla bir versiyonu yoktur. Yani çocuk ya da ebeveyn var ama amca ya
da hala yok. Ama eminim ki biz bir tane buluruz. Ama burada
denemeyeceğim, çünkü kulağa hoş gelmez. Pekiyi, y ile neden
ilgileniyorum? Çünkü ben bu yeniden renklendirme adımını yapıp
yapamayacağımı bilmek istiyorum.
Yeniden renklendirme düşüncesinde hatırlarsanız, büyük atalar diyelim ki
bu siyah. Eğer büyük atadaki siyahlığı aşağıdaki 2 ardılına
taşıyabilirsem, yani bunların ikisi de kırmızı ise, o zaman mutlu
olacağım. Bu nedenle problemi yukarıya taşırım. Buradaki öğe şimdilik
kırmızı.. Buradaki de siyah.. Bu nedenle bu ikisi şimdilik uygun
görünüyor. Şu eleman büyük büyük atayı ihlal edebilir. Ama öyle bir
durumda da yukarıya çıkmaya devam ederiz ve o zaman işler düzelir. Bugün
eğer şanslıysak, y kırmızı olacaktır.
Bu durumda yeniden renklendirme yapabiliriz. Eğer y’nin rengi kırmızıysa
o zaman bizi bunu yeniden renklendirebiliriz.
Ve ben bunu durum 1 adını verdiğim bir şemada göstereceğim. Ama
öncelikle size bu durumların nasıl oluştuğunu anlatayım; sonra da
onların nasıl çalıştığına bakalım.
Yani eğer durum 1 de değilsek bu “else”
yani “diğer” durum komutu bununla uyumlu olacaktır ve bu durumda ikinci
veya üçüncü durumda olacağız. İşte
dikotomi ya da ikiye bölme
işlemi buradadır. Aslında biz bütün durumları gördük; belki A’nın B’ye
karşıtlığını görmedik ama en başta sadece yeniden renklendirme durumunu
görmüştük. Bu Durum 1’dir.
Gördüğümüz ikinci şey büyük ata ve 10, yani 7 ve 10’un bir düz çizgide
olamamasıydı ve bu bizi rahatsız etti. Zikzaklı bir biçimde
yerleştirilmişlerdi. Böylece ikinci durum bunların zikzaklı durumunu
kapsar. Eğer x atasının sağ ardılıysa ve ata da büyük atanın sol
ardılıysa, bunun zikzak durumunu meydana getirdiğini varsaydık. Bu
ikinci durumdur.
Evet son durum da x’in atasının sol ardılı olmasıdır. Bu durumda x, x’in
atası ve x’in büyük atası arasında bir sol zincir elde edilir. Bu da
üçüncü durumdur. Buraya “else” yazmadım çünkü ikinci durumun yaptığı şey
3. Duruma indirgenmektir. Yani 2. Durumda buradaki işlemleri yapacağız
sonra şuradaki işlemleri yapacağız. 3. Durum için ise sadece şuradaki
işlemleri yapacağız. Birinci durumda ise buradaki işlemleri yapacağız.
Böylece bu A tarafındaki üç durumu bitirecek ve şuradaki “eğerden”
“else”e geçerek devam edeceğiz.
Burada söylenecek diğer şey bunun B durumu olduğu ve A durumu ile
aynı ama sol ve sağ kavramları açısından A’nın tersi olduğudur. Bu doğal
olarak oluşur.
Burada her sola bir şey yazdığımızda şurada onun sağına yazacağız veya
tersini yapacağız. Bu aslında sadece işi tersyüz etmek gibi bir şey. Şu
anda kategori A’ya odaklanacağız. Ve 3. durumda neler yaptığımızı
göreceğiz. Bunu bir örnekte görmüştük. Ama şimdi jenerik olarak bunu
yapalım. Bunu burada yapalım. Afedersiniz algoritmaya eklenmesi gereken
bir satır daha olduğunu söylemeliyim. Çünkü burayla uyumlu değil. Kökü
renklendiriyoruz. Burada olan şeyleri yaptıktan sonra kökün kırmızıya
dönüşme olasılığı var. Ama biz kökün her zaman siyah olmasını istiyoruz.
Kök eğer kırmızı olursa algoritmanın en sonunda bunu siyaha
dönüştüreceğiz. Bu siyah yükseklik özelliğini değiştirmez. Bu durumda
her şey uygun olur çünkü her yol ya köke gider veya gitmez; yani x -
yaprak yolu. Bu nedenle kökü kırmızıdan siyaha çevirmek bir sorun
oluşturmaz. Bu her şeyin siyah yüksekliğini arttıracaktır ama bütün
yollar hala aynı değerde olacaktır; yükseklik bir artacaktır.
Evet şimdi üç duruma bakalım. Ve burada birkaç simgelem kullanmak
istiyorum. Hatırlarsanız rotasyonu tanımlamamız sırasında rastgele alt
ağaçları belirtmek için üçgenler kullanmıştık. Ben bu alt ağacın siyah
bir kökü olduğunu anlatmak için üçgenin üzerine bir nokta koyacağım.
Burada kara tahtadayım onun için beyaz bir şey koyarsam bu aslında siyah
anlamına gelecek kusura bakmayın. Ayrıca bu üçgenlerin aynı siyah
yüksekliğine sahip olması gibi bir özelliği de var.
Böylece siyah yükseklik özelliğinin, yani 4. özelliğin korunduğuna dair
emin olmam sağlanacak. Şimdi size 1. Durumu göstereyim. Bu işlemi
yaparken 4.özelliğin her zaman korunmasını isteriz, çünkü bunu tekrar
eski hale getirmek çok zordur; Bu ağacın dengesini ifade eder. Şimdi C
adlı bir düğümümüz olsun, sol
ardılı A, sağ ardılı B olsun ve bunlardan da birkaç tane alt ağaç
sarksın. Ve bütün bu alt ağaçların siyah yüksekliği aynı olsun. Başka
bir ifadeyle bunların hepsi aynı düzeyde.
Bu tam anlamıyla benim istediğim şey değildi, bağışlayın. Benim
düşündüğüm bu düğümün x olmasıydı. x kırmızı ve onun atası da
kırmızı. Bu nedenle bir şeyi düzeltmemiz gerekiyor. Buradaki y düğümüne
burada bakarız. Ve ben buna D
anahtarını ayatacağım. Ama düğümün adı
y. Ondan sarkan alt ağaçlar da var ve hepsi de aynı siyah yükseklikte.
Ancak bu şekilde doğru olabilir. Bütün bu düğümler kırmızı olsaydı bütün
şu düğümlerin siyah yüksekliği
aynı olurdu. Bu nedenle bütün ardıl alt ağaçların, ki bunların hepsinin
siyah kökleri var, siyah yüksekliklerinin de aynı olması gerekir. Evet,
bu durumda büyük bir kırmızı ardıl alt ağaç grubuna bakıyoruz; bu bir
siyah düğümden sarkıyor ve içindeki bir çok öğe de kırmızı.
Birinci durumda kırmızı neden bu kadar yoğun? Bunun nedenini düşünürsek,
2,3,4 tipi ağaç yaratmaya çalıştığımızda bütün bu şeyleri tek düğümün
içine sığdırırdık. Burada temelde yaptığımız şey buydu. Bu 2,3,4 tipi
bir ağaç değil ama, şimdi 5 ardılımız var ve bu da kötü. Bu nedenle bunu
düzeltmeye çalışıyoruz. Böylece birinci durumda yeniden renklendirme
yapacağız. Önce C’yi alacağız. C’yi siyah yapmak ve A ile D’yi kırmızı
yapmak yerine A ile D’yi siyah ve C’yi kırmızı yapacağız.
Böylece C kırmızı olur. A siyahtır. D de siyahtır. Ve alt ağaçlar
aynıdır. B aynıdır. Hala kırmızıdır. Şimdi 4. özelliği koruyup
korumadığımızı kontrol etmek lazım; yani bütün yollarda aynı sayıda
siyah düğümün olduğuna bakmamız lazım. Bunun olması gerekiyor çünkü alt
ağaçlara dokunmadık. Onların hepsinin aynı siyah yüksekliği var. Bu
durumda eğer herhangi bir yola bakarsanız, örneğin A’da olan tüm yollara
bakarsanız bunların eşit siyah yükseklikleri olması gerekiyor. C’den
çıkan tüm yolların da siyah yüksekliklerinin bu değer artı 1 olması
gerekiyor, çünkü tüm sol yollarda bir siyah düğüm var ve tüm sağ yolarda
da bir siyah düğüm var. Bu nedenle tüm siyah linkler birbirinin aynı.
Böylece 4. özellik korunmuş olur. Ve bu da 3. özelliği yerel olarak
düzeltti, çünkü B eskiden A’yı ihlal ediyordu.
Şimdi B hiçbir şeyi ihlal etmiyor. Ancak şimdi C ihlal ediliyor
olabilir. Yapmamız gereken şey, yeni değerimiz x’i C’ye atamak. Daha
önce B’deydi. Bunu birkaç
düzey yukarıya taşırız. Aynı şekilde orijinal ağaçta da birkaç seviye
yukarı gideriz. Böylece ağaç boyunca yavaş yavaş ilerleriz. Ondan sonra
bu döngüyü sürdürürüz. Bu durum 1’dir: yeniden renklendir ve yukarıya
git. C kendi atasını ihlal edebilir ve bu durumda özyineleme yapmamız
gerekir. Yani bir şekilde özyinelemeyi C içinde südürüyoruz.
Şimdi ikinci duruma bakalım. Aslında hala bir bakıma
bu algoritmayı resimlerle tanımlıyorum. Bu güzel bir grafik
programlama dili. Haydi, 2. durumu çizelim. Ama bu noktada 1. durumla
ilgili bir şeyi söylemeyi unuttum. Buralara bir şeyler çizdim. Doğru
olduğunu bildiğim şey nedir? Şimdi terse çevirdiğim algoritmaya şöyle
bir bakalım. Unutmayın, henüz kategori A’da olduğumuzu varsayıyoruz.
Başka bir deyişle ata büyük atanın sol ardılı. Yani A, C’nin sol
ardılıdır. Bunun böyle olduğunu zaten biliyordum. Bu nedenle y sağ ardıl
oluyor. D ise C’nin sağ ardılı.
B’nin sağ ardıl mı yoksa sol ardıl mı olduğunu gerçekte bilmiyordum. Bu
fark etmiyordu. 1.durumda bu fark etmez. Bu nedenle “A’nın ardılları
terse çevrilebilir” demeliydim.
Ama aynı çizimi kullanabilirim. Bunu anlatmamın nedeni 2. durumda
bunun önemli olacağıdır.
Yani 1. Durumda bununla ilgilenmiyorduk. 2.durumda diyoruz ki x atasının
sağ ardılı mıdır yoksa sol ardılımıdır?
Eğer sağ ardılıysa o zaman 2. durumdayızdır. Bu durumda buradaki x’in,
ki bu B olarak gösteriliyor, A’nın sağ ardılı olduğunu bilebilirim. Daha
önce bilmiyordum ve ilgilenmiyordum. Şimdi bunun böyle olduğunu
varsayıyorum. Tamam y hala
şurada. Ve şimdi biliyoruz ki y siyahtır. Evet y burada ve siyah bir
düğüm. Şimdi o
sıkıştırma numarasını yaparsam bütün düğümler, yani A, B ve C tek bir
düğüm halinde bir araya gelecekler. Ve bu durumda sadece 4 ardılım
olacak. Bu gerçekte iyi görünür. y neden işin içinde değildir, çünkü
siyahtır. Bu nedenle bu durumda biz A’da sol rotasyon ya da dönme
yapacağız.
Böylece bu kenarı 90 derece çeviririz. Elde edeceğimiz şey A’nın solda,
B’nin de hala sağda olmasıdır. Bu düzen, sırasıyla geçiş olgusunu korur
ve C hala tepededir. y alt ağacı daha önce olduğu gibi buradan sarkar.
Öteki 3 alt ağaç B’den ve diğer ikisi de A’dan sarkıyor durumdadır. Yani
bu sadece bir jenerik rotasyon şeklidir ve bu kenara uygulanmıştır.
Bunun yaptığı iş daha önce x ile onun büyük atası arasında bir zikzak
vardı; şimdi
zigzig var. Yani x ile büyük
ata arasında düz bir yol var.
x hala burada, x’i değiştirmiyorum çünkü 2. Durumu yaptıktan sonra hemen
3. Duruma geçeceğim. Bu 3. Durumun nasıl göründüğüdür ve şimdi 3. Durumu
ele alacağım.
Sonunda 3. Duruma geldim. Ve bu araya yerleştirme algoritmasının sonu
olacak. Elimizde bir siyah düğüm var; C düğümu. C’den çıkan bir sol
kırmızı ardıl yani çocuk var. Bir kırmızı sol torun ve x var. Ve
bunlardan başka şu siyah altağaçlar var; bunlar aynı siyah yükseklikte
sarkıyorlar yani 2. Durumun sonunda elde ettiğimiz sonucun aynısı.
Bu tamamıyla ilişkili olarak buraya geçiyor. Ve unutmayın bu, kategori
A’da kalan tek durumdu. Kategori A’da biz x’in atası olan B’nin, büyük
ata olan C’nin sol ardılı olduğunu kabul etmiştik. Yani bunu biliyoruz.
1.durumu yaptık buradaki y kırmızı olmuştu. Bu 1. Durumdu. Şimdi biz
y’nin siyah olduğunu varsayıyoruz. Ve x’in sol ardıl mı yoksa sağ ardıl
mı olduğuna bakıyoruz. Eğer sağ ardılsa bunu sol ardıl haline
dönüştürüyoruz. x gerçekte burada değişti. Önceden x
B idi. Şimdi x A. Durum 3 te ise
büyük atanın sol çocuğu olan atanın sol çocuğudur. Bu bizim incelememiz
gereken son durum. Ve yapacağımız şey önceki örnekte yaptığımız gibi bir
rotasyon yapmak.
Bu 3. Durum. C’nin bu durumunda bir sağ rotasyon yapacağız. Ve aynı
zamanda yeniden renklendirme yapacağız. Böylece ne elde ederiz? Bu
durumda B kök olur. Ve bu nedenle onu siyah yapacağım. Hatırlayın bu alt
ağacın köküdür; buradan sarkan başka şeyler de var. Aslında bu
resimlerde ek ataları da çizmem lazımdı. Bunlar ağacın ortasında bir
yerlerde olmalıydı. Yerlerini şimdi bilmiyorum. Bu bir sağ dal olabilir:
aynı zamanda sol dalda olabilir. Şu anda bilmiyoruz. C, B’nin ardılı
olur ve onu kırmızı ardıl olarak işaretleyeceğim. A, daha önce olduğu
gibi B’nin ardılı olur ve o nedenle onu kırmızı bırakacağım. Bunun
dışında her şey buradan sadece sarkar durumda olur.
Böylece ortada 4 alt ağaç vardır ve bunların hepsinin siyah yüksekliği
aynıdır. Özellikle şu sonuncusu y’yi içeriyordu ama biz artık y ile
ilgilenmiyoruz. Şimdi artık iyi durumdayız çünkü başka ihlallerin
olmaması gerekiyor. Daha önce x ile onun atası A ve B arasında ihlal
vardı. Aslında A ve B’nin hala bir ata ardıl ilişkisi var ama B şimdi
siyah ve B siyah olduğu için bunun atasının neye benzediği bizi
ilgilendirmiyor. Kırmızı da olabilir, siyah da olabilir. Her ikisi de
olabilir. Kabul edilebilir. Artık 3. Özelliği ihlal etmiyoruz. Bu durumu
çözmüş olmamız gerekiyor.
3 özellik şimdi artık geçerli. Eğer isterseniz x artık bu düğüm oldu
diyebilirsiniz. Döngü de size “iyi artık x kırmızı değil” der. Bu
nedenle işim bitti. Aynı zamanda 4. Özelliğin de bu işlem sırasında
korunduğunu kontrol etmemiz lazım. Ve yine bu o kadar zor değil çünkü
2-3-4 ağaç transformasyonu oldu. Eğer bütün kırmızıları ataların içine
entegre edersem, bunun dışında her şey sabit olur yani aynı siyah
uzunluğa sahip oldukları için ağaç içinde de aynı uzunlukta olurlar. Ve
burada da bu hala geçerli. Burada buna biraz daha dikkat etmek gerekiyor
çünkü burada aynı zamanda yeniden renklendirme yapıyoruz. Ama bu
ağaçtaki herhangi bir yola bakarsanız daha önce bu yol siyah düğüm C’den
geçiyordu, sonra da beni ilgilendirmeyen bazı kırmızı yerlerden
geçiyordu. Sonra da bu
ağaçların içinden geçiyordu ve hepsi siyah yükseklikleri nedeniyle
birbirlerinin aynıydı.
Şimdi burada gelip adı B olan bir siyah düğümden
geçersiniz. Ondan sonra bazı
kırmızı düğümlerden geçersiniz. Bu çok fark etmez. Ama burada aşağı
doğru gittiğiniz tüm ağaçların siyah yükseklikleri aynıdır; yani aynı
düğümden başlamak kaydıyla bu
ağaçtaki her yolun siyah yüksekliği aynıdır. Böylece biz 4. Özelliği
korumuş oluruz ve 3. Özelliği düzeltiriz. Bu araya yerleştirme
algoritmasıdır. Oldukça uzundu. Bu büyük bir olasılıkla sizin
ezberlemeniz gereken bir şeydir.
Birkaç örnekle denerseniz o kadar zor olmadığını göreceksiniz. Bu
örnekte yaptığımız her şeyin 3 durumla ilgili olduğunu görebiliriz.
Birinci adımı yersizlik nedeniyle maalesef sildim ama, yaptığımız tek
şey yeniden renklendirmeydi. 10’a, 8’e ve 11’e yeni renkler verdik. Bu
birinci durumdu. 10, 15’in büyük atasıydı. 10’a baktık ve 10 ihlal eden
elemandı. Kendi büyük atasına göre bir zikzak durumu yaratıyordu. Bu
nedenle bir sağ rotasyon yaptık bunu düzelttik, yani köşelenmeyi
kaldırdık ve böylece 10, 7’nin yanına geldi.
Bu üstteki şekilde. Sonra 18 yeni ihlalci oldu kendi büyük atasıyla bir
uyumsuzluğu vardı. Her ikisi de aynı yöne gidiyordu. Bunu düzeltmek için
bir rotasyon daha yaptık. Aslında hatırlamamız gereken tek şey de budur.
Becerebiliyorsanız büyük atanızı yeniden renklendirin. Veya onu aynı
hatta getirin. Sonra bir son rotasyon daha yapın ve yeniden
renklendirin. Bu şekilde sistem çalışacaktır.
Eğer bunları hatırlarsanız herhangi bir örneğin gerisini
çözersiniz.
10’u döndürüyoruz. Bu siyah olsa iyi olur, çünkü bu durumda bu kök
haline geliyor. Ama ne olursa olsun bunu siyaha döndüreceğiz çünkü orada
bir siyah düğüm olması gerekiyor. Eğer aynı zamanda bunu yeniden
renklendirmezsek 4. özelliği ihlal ederiz. Ben bunu niye çizmiyorum ki,
aslında birkaç dakikam var. Yani eğer rotasyonu burada yapsaydık;
aşağıdakinden farklı olarak B’yi alacağız.
B kırmızı. Bu size algoritmanın niye böyle olduğu ve niye başka türlü
olmadığı konusunda sezgisel bir yaklaşım getirecektir. Ve C siyah. Eğer
bu ağacı döndürseydik yani B’yi döndürseydik veya C’yi sağa döndürseydik
elde edeceğimiz şey buydu. Bu aşağıdaki alt ağaçlar aynı şekilde
sarkıyorlar. Alt ağaçlar çok iyi görünüyorlar çünkü hepsinin siyah
yükseklikleri aynı. Ama gördüğünüz gibi bir problem var. Eğer B’den
başlayıp aşağıdaki yaprağa gidecek olan yollara bakarsak sol taraftaki
siyah düğümlerin sayısı aşağıdaki siyah yüksekliklerine bağlı.
Bunu kaydedin: siyah yüksekliği. Sağdaki tüm yolların siyah yüksekliği,
C siyah olduğu için bu yükseklik artı 1 olacaktır. Şimdi biz dördüncü
kuralı ihlal ettik. Bu nedenle bunu 3. Durumda yapmayız. Rotasyonu
tamamladıktan sonra yeniden renklendirmeyi de yaparız. Ve bunu elde
ederiz. Başka bir deyişle siyah düğümü tepeye
koyduk çünkü tüm yollar o düğümden geçmek
durumundadır. Oysa ki burada bazı düğümler C ’den geçiyor. Bazıları A
‘dan geçiyor. Bu durum kötü. Bu durumda biz 3. Özelliği de ihlal
ederdik. Ama daha da kötüsü burada biz 4. Özelliği ihlal ediyoruz. Şimdi
birazcık bunları özetleyelim.
Şu ana kadar; eğer kırmızı siyah bir ağaçta araya yerleştirme yaparsak o
ağacı kırmızı siyah olarak muhafaza edebiliriz. Yani kırmızı siyah araya
yerleştirme dinamik sete bir x değerini ekliyor ve bunu aynı zamanda
muhafaza ediyor ve kırmızı siyahlık olgusunu koruyor. Yani kırmızı siyah
ağaç olgusunu muhafaza ediyor; bu iyi çünkü bu durumda logaritmik
yükseklik de korunur. Böylece kırmızı siyah ağaçlarda yapılan bütün
sorgulamalar logaritmik zaman alır. Kırmızı siyah araya yerleştirmeler
ne kadar zaman alır? Biliyoruz ki hazırlık zamanı için
hedefimiz log n düzeyinde. Bunu
resmi olarak kanıtlamayacağım ama sezgisel olarak çok açık görünüyor
olması lazım. Böylece 2. Ve 3. durumlar pardon yanlış yere işaret
ediyorum 2. Ve3. Durumlar son durumlardır.
3.durumu yaptığımızda işimiz biter. 2.durumu yaptığımızda 3. Durumu
yapmanın başına geliriz ve ondan sonra işimiz biter. Böylece gerçekten
sayma ihtiyacımız olan durum birincisidir, çünkü bütün bu yeniden
renklendirme, rotasyon gibi işlemler sabit zaman alır. Bu durumda mesele
bunlardan kaç tane olduğudur. 1. Durumda sadece yeniden renklendirme
yapılır bu ağacı hiçbir zaman değiştirmez ve x’i sadece iki düzey
yukarıya taşır.
Ağacın yüksekliğinin en çok 2 log (n+1) olduğunu biliyoruz. Yani Durum 1
lerin sayısı en çok log(n+1) olabilir. Yani durum 1’lerin sayısı en çok
log n olur. Yani bunlar log n zaman alır. Ondan sonra 2.ve 3. Durumların
sayısı bu kolonlardan biri için en çok 1’dir. Her ikisini bir araya
getirirsek 2. Ve 3. Durumlar için en çok 2 elde ederiz. Evet sonunda log
n zamanı, bu iyi. Kırmızı siyah araya yerleştirmelerin enteresan bir
yönü de bunların sadece birinci düzey rotasyonları gerektirdiğidir.
Yani değişikliklerin çoğu yeniden renklendirmededir. 1.durumda
sadece yeniden renklendirme yapılır, rotasyon yapılmaz. 2.durumda belki
bir rotasyon yapılır. Eğer 3. Duruma gerek kalırsa bir rotasyon
yapılacak; böylece rotasyonların toplam sayısı 2 olur. Yani araya
yerleştirme de bu 1 veya 2 tanedir.
Bu aslında hoş bir durum çünkü bir ağacı döndürmek o ağacı boyamaktan
daha rahatsız edici bir durumdur. Neden? Çünkü diyelim ki bir veri
yapınız var, yani bir arama ağacınız var. Teorik olarak insanlar bu
arama ağacını bir şeyler için kullanmak isterler. Örneğin, burada
sorgulamalar yaparlar. Mesela Google’da computer sözcüğü ile çakışan tüm
dokümanlar bir arama ağacıyla temsil edilir. Şurada bir Google T-shirti
var Onun için burada Google’ı referans olarak kullanabiliriz.
Bir arama ağacı var. Bu arama ağacı Google sözcüğüne ilişkin her şeyi
depoluyor. Belki bir tarihten sonra değiştirilmiş olan bir şeyi burada
aramak istiyorsunuz ve bu ağaçta bir takım sorgulamalar yapıyorsunuz. Ve
insanlar Google’ı sorgulamalarla neredeyse yumrukluyorlar. 1 saniyede
neredeyse zilyon tane sorgulama geliyor. Bu konuda sakın bana atıfta
bulunmayın. Çünkü rakam doğru olmayabilir. Evet zilyon.
Ama insanlar sürekli arama yapıyorlar. Ve siz ağacı yeniden
renklendirdiğinizde insanlar hala arama yapabilirler; sizin
değiştirdiğiniz küçük bir parçadır. Ben arama yaptığımda bir düğümün
kırmızı mı siyah mı olduğuyla ilgilenmem, çünkü her ikisinin de
logaritmik yüksekliği vardır.
Böylece siz arama yapanlar web’de sörf yaparken de gelip ara sıra
güncellemeler uygulayabilirsiniz. Ve bu açıdan yeniden renklendirme çok
iyidir. Rotasyon ise buna göre biraz daha pahalıdır; çünkü işi yaparken
önce düğümleri kilitlersiniz, onları döndürme sürecinizde kimsenin ona
dokunmamasını istersiniz. Ondan sonra kilidi açarsınız. Yani rotasyon
sayısının gerçekten az olması sadece 2 olması çok güzeldir. Sürenin de
log n’yi geçmemesi lazım çünkü temelde sıralı bir listeye araya
yerleştirme yapıyoruz. Bu durumda, eğer n sayısında araya yerleştirme
yaparsak, alt sınırımız da n log n olur. Pekiyi, silme; şimdi burada
bunu incelemeyeceğim.
Bunu kitaptan okumalısınız. Biraz daha karmaşıktır ama aynı fikirlere
dayanır. Aynı sınırlamalara bağlıdır: log n zamanı ve 1.düzeyde
rotasyonlar. Bu nedenle bunu inceleyin. Bu kırmızı siyah ağaçlardır.
Şimdi artık verileri log n zamanlı hazırlık zamanında işleyebilir ve
bakımını yapabilirsiniz. Bu iyi bir şeydir. İleride bunu yapmanın 3
yolunu göreceğiz.
Ders bitmiştir. |