Professional Documents
Culture Documents
8 Veriyapilari
8 Veriyapilari
1. Ardışıl Arama
2. İkili Arama
3. Hash (Çırpı) Fonksiyonu ile Arama
Ardışıl Arama
• Ardışıl arama en basit arama algoritmasıdır. İlk elemandan
başlanarak aranan eleman bulununcaya ya da veri kümesinin
sonuna erişinceye kadar aramaya devam edilen algoritmadır.
• Ardışıl aramanın en kötü durumdaki algoritman karmaşıklığı
𝑂(𝑛) dir.
aranan
Bu mu?
Bu mu? Evet
v1 v2 v3 v4 v5
Ardışıl Arama (Örnek Kod)
#include <iostream>
using namespace std;
ardisilArama(int A[], int N, int aranan){
for(int k=0;k<N;k++){
if(A[k]==aranan) return k;}
return -1;}
int main(){
int B[]={13,12,4,5,9,24,36,2,0,-9}, ara, indis;
cout<<"Aranan Sayiyi Giriniz : "; scanf("%d",&ara);
indis=ardisilArama(B,10,ara);cout<<endl;
if(indis==-1)
cout<<"Aranan Bulunamadi :(";
else
printf("Aranan Sayi %d indisli elemandir",indis);
}
İkili Arama Algoritması
• İkili arama halihazırda sıralı olan veriler üzerinde çalışan bir algoritmadır,
yani bu algoritmanın kullanılması için üzerinde arama yapılacak veri
önceden sıralanmış olmalıdır. Bu açıdan bakıldığında bir telefon rehberi
veya sözlükte aramaya benzer.
• İkili aramanın algoritma karmaşıklığı 𝑂 log 𝑁 dir. Kayıt sayısı çok fazla
olan veriler için uygundur. Örneğin 1000000 tane veri içeren bir kümede
arama işlemi log 2 1000000 ≅ 20 olduğundan arama işlemi yaklaşık 20
işlem sonucunda tamamlanacaktır. Aynı işlem ardışıl sıralama ile
yapılsaydı, en kötü durumda 1000000 işlem gerekirdi.
• Aşağıdaki örnekte 45 aranandır. Dizi ikiye bölünür ve ortadaki eleman ile
aranan karşılaştırılır. Eğer bulunursa değer geri gönderilir. Değilse sağ ve
sol indisler aranandan küçük veya büyük olmasına göre hareket ettirilir
ve tekrar ortadaki elemana bakılır. Döngü bu şekilde devam eder.
0
1 Metin 111
Dizi Elemanları
2 Hasan 122
Metin 111
3
Hasan 122 anahtar Hash
4 Ali 133
Fonksiyonu
Ali 133 5
Mehmet 144 6 Mehmet 144
Recep 155 7
8 Recep 155
Anahtar bilgisi
9
Hash Fonksiyonu
• Hash Fonksiyonu ;
• Hesaplama açısından basit olmalıdır.
• Anahtar bilgisi için indis üretir
• Muhtemel Problemler:
• Anahtar bilgisi numerik olmayabilir.
• Farklı anahtarlar aynı indisi üretebilir (çarpışma).
• Eğer çok fazla çarpışma olursa hash fonksiyonunun
performansı dramatik olarak düşer.
• Eğer anahtar verisi integer ise en basit hash fonksiyonu
Anahtar mod TabloBoyutu şeklinde olabilir.
• Eğer anahtar string bir veri ise bu durumda daha dikkatli olmak
gerekir. Örneğin string önce bir sayısal değere dönüştürülüp
ardından hash fonksiyonuna gönderilebilir.
Hash Fonksiyonu (Örnek)
Örneğin Hash Fonksiyonu H(x) = x % 21 ise aşağıda
verilen x değerleri için H(x) değerleri ne olur ?
x = 22 214 45 1253 5 28
H(x) = 1 4 3 14 5 7
22 45 214 5 28 1253
1 71 1
2 52 12
3
5 5
6 6 16
7
9 49 9
Ayrık Zincirleme Üzerinde İşlemler
• Başlangıç: Tüm dizi eşemanları bir bağlı liste için işaretçi olarak
tanımlanır ve başlangıçta NULL değeri atanır.
• Arama:
– İlk önce hash fonksiyonu ile ilgili dizi hücresi bulunur.
– Ardından o hücredeki işaretçinin gösterdiği listede arama yapılır.
• Ekleme:
– İlk önce hash fonksiyonu ile ilgili dizi hücresi bulunur.
– Ardından o hücredeki işaretçinin gösterdiği listenin başına yeni
elemanı ekle.
• Silme:
– İlk önce hash fonksiyonu ile ilgili dizi hücresi bulunur.
– Ardından o hücredeki işaretçinin gösterdiği listede ilgili elemanı
sil.
Tek Yönlü Bağlantılı Liste ile Ayrık Zincirleme Uygulaması
#include <iostream>
#include<stdlib.h>
using namespace std;
int main()
{
BAGLISTE *eklenecek, *ki;
int bilgi, sonuc;
char secim;
while(1){// Ekrana Menü çıkarılıyor
cout<<endl<<"Ekleme"<<endl<<"Listeleme"<<endl<<"Arama"<<endl<<"Silme"<<endl<<"Cikis"<<endl<<"Seciminiz ?"<<endl;
cin>>secim;
switch(secim)
{
case 'E':
{ eklenecek=okuKlavye(); //ekleme secildi
if (eklenecek!=NULL) ekle(eklenecek);
else cout<<endl<<"Ekleme icin bellek dolu ! "<<endl;
break;
}
case 'L':// listeleme seçildi
{ listele();
//if (sonuc==1) cout<<endl<<"Bos Liste ! "<<endl;
break;
}
// Devami arka sayfada
Tek Yönlü Bağlantılı Liste ile Ayrık Zincirleme Uygulaması
case 'A': // Arama secildi
{ cout<<endl<<"Aranan: ";
scanf("%d",&bilgi);
ki=ara(bilgi);
if (ki==NULL) cout<<endl<<"Aranan Bulunamadi ! "<<endl;
else yazEkrana(ki);
break;
}
case 'S': // Silme secildi
{ cout<<endl<<"Silinecek: ";
scanf("%d",&bilgi);
ki=sil(bilgi);
if (ki!=NULL) cout<<endl<<"Silindi ! "<<endl;
else cout<<"Silinmek istenen veri listede yok ! "<<endl;
break;
}
case 'C':// Çıkış seçildi
{ cout<<"HOSCAKAL :) "<<endl;
exit(0);
}
default:cout<<"Yanlıs Secim !! "<<endl;
}
}
system("pause");
return 0;
}// Devami arka sayfada
Tek Yönlü Bağlantılı Liste ile Ayrık Zincirleme Uygulaması
// fonksiyonlar
void yazEkrana(BAGLISTE *yazilacak){
printf(" %d ",yazilacak->bilgi);}
BAGLISTE *okuKlavye(){
BAGLISTE *okunan;
okunan=new BAGLISTE;
if (okunan==NULL)
return NULL;
cout<<"Bilgi Giriniz"<<endl;
scanf("%d",&(okunan->bilgi));
okunan->arka=NULL;
return okunan;
}
int hash(int val){
int ind=val%10;
return ind;
}
Ayrık Zincirleme Analizi
x x x x x x x x x x x x x x x
Karesel (Quadratic) Araştırma
• Karesel araştırma birincil kümelenme problemini çözmek için
geliştirilmiştir.
• Çarpışma fonksiyonu kareseldir: 𝑓 𝑖 = 𝑖2
• Eğer hash fonksiyonunun ürettiği indis(ℎ) sonuç üretmezse bu durumda
bir sonraki indis(ler) ℎ + 12 , ℎ + 22 …. ℎ + 𝑖2 şeklinde bir sırayla seçilir.
– Örneğin karesel araştırmada hash fonksiyonu ile elde edilen indis h=0
olursa ve sonuç elde edilememişse bir sonraki indis 1, 4, 9 şeklinde
gider.
• Şunu unutmayalım ki sonraki indisler orijinal indisin kareleri şeklinde
ilerler.
Örnek
Karesel araştırmada her
veri yerleşiminden sonra
tablonun durumu
Karesel Araştırma-Analiz
• Problem:
– Tablodaki tüm hücrelerin araştırılacağından emin olamayız.
– Eğer Tablo Boyutu asal bir sayı değilse bu problem daha da muhtemeldir.
• Teorem: Eğer Tablo Boyutu bir asal sayı seçilirse ve yükleme faktörü 0.5 ten büyük değilse gelecek
herhangi bir veri mutlaka tabloya yerleşecektir.
• Teorem ispatı: Varsayalım ki Tablo Boyutu M olsun ve M asal olsun. Hedefimiz ilk M/2 adet
hücrenin ayrık olduğunu göstermek.
• Bu hücrelerin iki tanesi h+i2 ve h+j2 olsun ve i ve j için 00 ≤ 𝑖, 𝑗 ≤ 𝑀/2 olsun; Zıtlıkla ispat etmek
için varsayalım ki bu iki hücre aynı ama i ≠ 𝑗 olsun; Buradan;
ℎ + 𝑖2 = ℎ + 𝑗2 (𝑚𝑜𝑑 𝑀)
𝑖2 = 𝑗2 (𝑚𝑜𝑑 𝑀)
𝑖2 − 𝑗2 = 0 (𝑚𝑜𝑑 𝑀)
(𝑖 − 𝑗)(𝑖 + 𝑗) = 0 (𝑚𝑜𝑑 𝑀)
• Bu sonuçlara göre M asal olduğu için ne (𝑖 − 𝑗) ne de (𝑖 + 𝑗) M in bir bölenidir. Dolayısıyla burada
bir zıtlık vardır.
• Bu zıtlık bize eğer tablonun en fazla yarısı doluysa (yükleme faktörü 0.5) ilk M/2 sayıdaki
hücrelerin tamamının ayrık olduğunu ve tabloda m/2 tane boş hücre olduğu için gelecek bir
verinin tabloya yerleşeceğini garanti eder.
Bazı Önemli Noktalar
– Doğrusal araştırma kolayca uygulanabilir. Karesel araştırma çarpma ve mod
alma gerektirir.
– Eğer yükleme faktörü çok büyürse ne yapabiliriz?
– Tablo Boyutunu yükleme faktörünü 0.5 civarında tutacak şekilde dinamik
olarak değişecek olarak belirle. Bu işleme tekrar hashleme denir.
– Tablo boyutunu daima bir öncekinin yaklaşık iki katı olan bir asal sayıya
eşitle
– Taabloyu genişletirken, eski tabloyu yeni tabloya yeni hash fonksiyonu
yardımıyla yerleştir.
– Karesel araştırma birincil kümelenme için bir çözümdür ancak peki ikincil bir
kümelenme olursa;
– Çift Hashleme (Double Hashing) kullan
Araştırma Ödevi: Double Hashing
Hashing Uygulama Örnekleri ve Özet
Derleyiciler kullanıcı tarafından tanımlanan değişkenlerde kullanılan
sembollerin tablosunu tutmak için hash tablosunu kullanırlar.
Oyun programlarında hareketli nesnelerin uğradığı pozisyonların takibi için
hash tabloları kullanılır.
ÖZET:
Hash tabloları ortalama bir sürede bir tabloya veri ekleme ve arama için
kullanılabilirler.
Arama süresi tablonun boyutuna değil yükleme faktörüne bağlıdır.
Tablo boyutu belirlenirken asal sayı olan bir boyut seçmek önemlidir. Ayrıca
doğru hash fonksiyonu ve uygun yükleme fonksiyon değeri de önemlidir.
Eğer ayrık zincirleme kullanılacaksa yükleme faktörü 1’e yakın olmalıdır.
Eğer açık adresleme yapılacaksa bu durumda yükleme faktörü 0.5 i
geçmemelidir.