Veri Yapıları · Ünite 2
Dizi, Sözlük, Küme ve Listeler (C#)
10 soruluk deneme testine geç ↓1. Diziler (array)
Dizi, aynı türden birçok değeri bitişik bellek hücrelerinde tutar. Her elemanın yeri, ilk elemanın adresine bir ofset (kayma) eklenerek hesaplanır; bu yüzden erişim çok hızlıdır.
Tek boyutlu dizi
C#'ta indis 0'dan başlar, son indis «uzunluk − 1»dir. «anadolu» harflerini tutan 7 elemanlı dizide ilk harf [0]'da, son harf [6]'da.
int[] sayilar; // tanımlama (bildirim)
sayilar = new int[7]; // 7 eleman, hepsi 0
sayilar[0] = 12; // değer atama
int[] a = new int[] { 13, 4, 26, -7, 0 };
int[] b = { 13, 4, 26, -7, 0 }; // kısa yazım
int orta = a[2]; // 26Diziyi gezmenin en kolay yolu foreach: «foreach (string ay in aylar) Console.WriteLine(ay);» her elemanı sırayla yazar.
Çok boyutlu dizi
Tablo gibi satır–sütun. Boyutlar köşeli parantez içinde virgülle ayrılır.
int[,] tablo = new int[3, 6]; // 3 satır, 6 sütun
int[,,] kup = new int[2, 3, 4]; // 3 boyutlu
int[,] m =
{
{ 4, -6, -7 },
{ -11, 4, 0 },
{ -12, -9, 15 },
};
int x = m[2, 2]; // 3. satır, 3. sütun → 15
m[1, 0] = 5;Pürüzlü dizi (jagged array, dizi dizisi)
Her elemanı başka bir dizi olan tek boyutlu dizi. İç dizilerin uzunlukları farklı olabilir, hatta biri hiç atanmamış (null) kalabilir.
int[][] p = new int[4][]; // 4 eleman, hepsi null
p[0] = new int[] { 13, 0, 19 };
p[1] = new int[] { 7, 21, 5, 2, 71 };
// p[2] null kalır
p[3] = new int[] { 26 };
int s = p[1][2]; // 5
p[1][3] = 20; // 2 → 202. Hash tablosu (Hashtable)
Anahtar (key) → değer (value) eşleşmesi tutar; diğer adı hash map. Amacı: anahtarı verilen değeri O(1) sürede, yani koleksiyon ne kadar büyük olursa olsun neredeyse tek adımda bulmak.
- →Hash fonksiyonu anahtarı bir kova (bucket) numarasına çevirir. Böylece tüm elemanları tek tek gezmeye gerek kalmaz.
- →İdeali her anahtara farklı kova. İki farklı anahtar aynı kovaya düşerse buna hash çakışması (collision) denir ve ayrıca çözülmesi gerekir.
- →Kullanım: ilişkisel diziler, veritabanı indeksleri, önbellek sistemleri.
C#'ta hazırı var: System.Collections içindeki Hashtable sınıfı. Her çift bir DictionaryEntry nesnesidir (Key ve Value özellikleri).
Hashtable sayiIsim = new Hashtable();
sayiIsim.Add(1, "Bir");
sayiIsim.Add(2, "İki");
// sayiIsim.Add(2, "İki"); → çalışma zamanı hatası: anahtar zaten var
string deger = (string)sayiIsim[1]; // tür dönüşümü gerekir
foreach (DictionaryEntry e in sayiIsim)
Console.WriteLine($"{e.Key} - {e.Value}");| Üye | Ne yapar? |
|---|---|
| Count | Eleman sayısı |
| Keys / Values | Anahtarların / değerlerin listesi |
| Add, Remove, Clear | Ekle, sil, hepsini sil |
| Contains, ContainsKey | Bu anahtar var mı? |
| ContainsValue | Bu değer var mı? |
3. Sözlük (Dictionary) ve sıralanmış sözlük
Hashtable'ın sorunu: anahtar ve değer object türünde tutulur. Her okumada tür dönüşümü, arka planda da kutulama / kutudan çıkarma (boxing / unboxing) gerekir. Dictionary<TKey, TValue> bu sorunu çözer: türleri baştan belirtirsin, dönen değer zaten doğru türdedir.
var sozluk = new Dictionary<string, string>
{
{ "elma", "apple" },
{ "kitap", "book" }
};
string d = sozluk["elma"]; // dönüşüm yok
sozluk["kalem"] = "pen"; // yoksa ekler, varsa günceller
foreach (KeyValuePair<string, string> cift in sozluk)
Console.WriteLine($"{cift.Key} - {cift.Value}");Olmayan bir anahtarı istersen KeyNotFoundException fırlatılır. Bundan kaçınmanın üç yolu: try-catch bloğu, önce ContainsKey ile kontrol, ya da TryGetValue kullanmak. Okuma, ekleme ve güncelleme O(1)'e yakındır.
SortedDictionary: anahtarları her zaman sıralı tutar. 1, 4, 5, 3, 2 anahtarlarıyla eklenen isimler foreach'te 1, 2, 3, 4, 5 sırasıyla gelir. Bedeli: okuma, ekleme ve silme O(log n).
| Dictionary | SortedDictionary | SortedList | |
|---|---|---|---|
| Sıra | Yok | Anahtara göre sıralı | Anahtara göre sıralı |
| Okuma | ≈ O(1) | O(log n) | O(log n) |
| Ekleme / silme | ≈ O(1) | O(log n) | O(n) |
| Bellek | — | SortedList'ten fazla | Daha az |
4. Kümeler (HashSet, SortedSet)
Küme: tekrarsız ve sırasız elemanlar topluluğu. Bir elemanın «kümede olup olmadığını» hızla sorarsın. HashSet'i, değeri olmayan, yalnızca anahtar tutan bir sözlük gibi düşünebilirsin.
| İşlem | Gösterim | Sonuç (örnekte) | HashSet metodu |
|---|---|---|---|
| Birleşim | A ∪ B | {1, 2, 3, 4, 5} | UnionWith |
| Kesişim | A ∩ B | {3, 4} | IntersectWith |
| Fark | A \ B | {1, 2} | ExceptWith |
| Simetrik fark | A ∆ B | {1, 2, 5} | SymmetricExceptWith |
- →Alt küme: B'nin her elemanı A'da da varsa B ⊆ A (IsSubsetOf); A da B'nin üst kümesidir (IsSupersetOf).
- →Uygun (proper) alt küme: B ⊆ A ama B ≠ A (IsProperSubsetOf / IsProperSupersetOf).
- →SetEquals: iki küme aynı elemanlara mı sahip? Overlaps: en az bir ortak eleman var mı?
- →Ayrıca Add, Remove, Clear, Contains ve Count.
Örnek kullanım: indirim kodlarını bir HashSet<int>'te tutmak. Girilen kod Contains ile kontrol edilir; varsa «bu kod kullanıldı», yoksa Add ile eklenir. Aynı kodu iki kez saklamak zaten imkânsız.
SortedSet: tekrarsız ama sıralı küme (HashSet + sıralı liste karışımı). HashSet'in metotlarına ek olarak Min, Max ve belli aralığı veren GetViewBetween var. Büyük/küçük harf duyarsız bir karşılaştırıcı verilirse «Melek» ile «melek» tek eleman sayılır.
5. Listeler (ArrayList, List<T>)
Kaç eleman tutacağını bilmiyorsan dev bir dizi açmak yerine boyutu kendiliğinden büyüyen bir yapı kullan.
ArrayList
ArrayList liste = new ArrayList();
liste.AddRange(new int[] { 4, 3, -1 }); // sona koleksiyon ekle
liste.Add(7); // sona tek eleman
liste.AddRange(new object[] { "Rabia", "Elif" });
liste.Insert(5, 7.8); // 5. indise yerleştir
// → 4, 3, -1, 7, Rabia, 7.8, Elif
int ucuncu = (int)liste[2]; // dönüşüm gerekir- →Elemanlar object tutulur, bu yüzden farklı türler aynı listede durabilir (sayı, metin, ondalık).
- →Count eleman sayısı; Capacity ayrılmış yer. Eleman ekledikçe Capacity otomatik büyür.
- →Contains → true/false. IndexOf ilk, LastIndexOf son konumu verir; bulamazsa −1 döner.
- →Remove(değer) ilk geçtiği yeri, RemoveAt(indis) o indisi, RemoveRange(i, n) i'den başlayarak n elemanı siler. Clear hepsini, Reverse sırayı ters çevirir, ToArray diziye dönüştürür.
List<T> (generic liste)
ArrayList'in tür güvenli (strongly typed) sürümü; System.Collections.Generic'te. Türü baştan belirtirsin: List<int>, List<string>, List<Ogrenci>. Metot adları ArrayList'le aynı.
- →Derleme zamanında tür denetimi yapar; boxing/unboxing yok.
- →ArrayList'ten daha hızlı ve daha az hataya açık.
- →Eleman: Add, AddRange ya da koleksiyon başlatıcı { … } ile eklenir; liste[0] ile okunur.
- →Türü izin veriyorsa null eklenebilir (List<string> gibi).
var asallar = new List<int>() { 2, 3, 5, 7 };
asallar.Add(11);
Console.WriteLine(asallar.Count); // 5
// Üç gezinme yolu, aynı çıktı:
asallar.ForEach(x => Console.Write(x + " "));
foreach (var x in asallar) Console.Write(x + " ");
for (int i = 0; i < asallar.Count; i++) Console.Write(asallar[i] + " ");Hepsi bir arada
| Yapı | Ne zaman? |
|---|---|
| Dizi | Eleman sayısı belli ve sabit, hızlı indis erişimi lazım. |
| Hashtable | Anahtarla hızlı arama; türler karışık (eski, generic olmayan). |
| Dictionary | Anahtarla hızlı arama, türler belli. Çoğu durumda ilk tercih. |
| SortedDictionary | Anahtarlar hep sıralı lazım. |
| HashSet | Tekrarsız elemanlar, «var mı?» sorusu, küme işlemleri. |
| SortedSet | Tekrarsız ve sıralı; Min / Max lazım. |
| List<T> | Boyutu değişen, tek türlü liste. |
| ArrayList | Boyutu değişen, karışık türlü liste (eski). |
Kendini test et!
Cevabı görmek için soruya dokun.
1.int[] d = new int[5]; satırından sonra d[4] kaçtır, d[5] ne olur?
✓ d[4] = 0 (varsayılan). d[5] yok: indisler 0–4, erişmeye çalışmak hata verir.
2.int[][] p tanımlı ve p[2] null. p[2][0]'ı okumak neden hata verir?
✓ Pürüzlü dizinin 3. elemanına hiç iç dizi atanmamış; null bir dizinin elemanı okunamaz.
3.Dictionary'de olmayan bir anahtarı istemek hangi hatayı verir, nasıl önlenir?
✓ KeyNotFoundException. try-catch, ContainsKey ile kontrol ya da TryGetValue kullanılır.
4.A = {2, 4, 6, 8}, B = {6, 8, 10}. A ∆ B nedir?
✓ {2, 4, 10}: yalnızca bir kümede olanlar.
5.ArrayList'te 4, 3, 4, 9 var. IndexOf(4) ve LastIndexOf(4) ne döndürür? IndexOf(5)?
✓ 0 ve 2. IndexOf(5) bulamadığı için −1.
6.List<int> neden ArrayList'ten daha hızlıdır?
✓ Türü baştan bellidir; elemanları object'e kutulayıp geri çıkarmak (boxing/unboxing) gerekmez.
Deneme testi
Sınavda çıkabilecek türden 10 soru. Bir şık seç; doğru cevap ve açıklaması hemen çıkar.
1.C#'ta aşağıdaki dizi tanımlamalarından hangisi hatalıdır?
2.int[][] sayilar = { new int[] { 13, 0, 19 }, new int[] { 7, 21, 5, 2, 71 } }; için sayilar[1][2] kaçtır?
3.Hash tablosunda anahtardan, değerin bulunduğu kovanın numarasını hesaplayan bileşen hangisidir?
4.Hashtable ve Dictionary için aşağıdakilerden hangisi doğrudur?
5.Anahtarları her zaman sıralı tutan, ekleme ve silmesi O(log n) olan yapı hangisidir?
6.A = {1, 2, 3, 4} ve B = {3, 4, 5} ise A \ B kümesi hangisidir?
7.İki kümenin en az bir ortak elemanı olup olmadığını kontrol eden HashSet metodu hangisidir?
8.ArrayList'te aranan değer bulunamazsa IndexOf metodu ne döndürür?
9.List<T>'nin ArrayList'e göre üstünlüğü aşağıdakilerden hangisidir?
10.Dictionary'de olmayan bir anahtara erişmeye çalışınca oluşan hatadan kaçınmak için hangileri kullanılabilir? I. try-catch II. ContainsKey III. TryGetValue
Bu not ders kitabının yerine geçmez; konu kendi cümlelerimizle, yapay zekâ desteğiyle özetlendi.