Veri Yapıları Hakkında
Veri yapıları, bilgisayar biliminin temel taşlarından biridir. Basitçe ifade etmek gerekirse, verileri bilgisayarın belleğinde (RAM) en verimli şekilde saklama, organize etme ve bu verilere en hızlı şekilde erişme yöntemleridir. Yazılımın hızı, sadece yazdığınız algoritma ile değil, seçtiğiniz veri yapısı ile belirlenir. İşte bir yazılım geliştirici gözüyle temel veri yapıları rehberi:
1. Temel Veri Yapıları Sınıflandırması
Veri yapıları genellikle iki ana gruba ayrılır:
Doğrusal (Linear) Veri Yapıları
- Verilerin sırayla dizildiği yapılardır.
- Diziler (Arrays), Yığınlar (Stack) ve Kuyruklar (Queue) gibi veri yapıları bu gruba aittir.
Doğrusal Olmayan (Non-Linear) Veri Yapıları
- Verilerin hiyerarşik veya rastgele bağlantılı olduğu yapılardır.
- Ağaçlar (Trees) ve Hash Tabloları (Hash Tables) gibi veri yapıları bu gruba aittir.
2. En Sık Kullanılan Veri Yapıları
A. Diziler (Arrays)
- En temel veri yapısıdır.
- Veriler bellekte yan yana (sıralı) kutucuklarda tutulur.
- Avantajı: İndeks numarasıyla (örneğin dizi[5]) veriye erişim inanılmaz hızlıdır.
- Dezavantajı: Boyutu genellikle sabittir; aradan bir eleman silmek veya eklemek diğer tüm elemanların kaydırılmasını gerektirdiği için maliyetlidir.
B. Bağlı Listeler (Linked Lists)
- Elemanlar bellekte dağınık halde bulunur ancak her eleman kendinden bir sonraki elemanın adresini (pointer) tutar.
- Avantajı: Dinamiktir; araya eleman eklemek veya silmek sadece adresleri değiştirmeyi gerektirdiği için çok kolaydır.
- Dezavantajı: Belirli bir elemanı bulmak için listenin başından itibaren tek tek ilerlemek gerekir (rastgele erişim yoktur).
C. Yığın (Stack - LIFO)
- "Son Gelen İlk Çıkar" (Last In, First Out) prensibiyle çalışır.
- Kirli tabak yığını veya bir metin belgesindeki "Geri Al" (Undo) işlemi en klasik örneğidir.
- Temel İşlemler: push (ekle), pop (en üsttekini çıkar).
D. Kuyruk (Queue - FIFO)
- "İlk Gelen İlk Çıkar" (First In, First Out) prensibiyle çalışır.
- Market sırası veya yazıcıya gönderilen belgelerin sırası gibidir.
- Temel İşlemler: enqueue (sıraya ekle), dequeue (sıradan çıkar).
E. Ağaçlar (Trees)
- Verilerin hiyerarşik bir düzende saklandığı yapılardır.
- En üstte bir "Kök" (Root) ve ona bağlı "Dallar" (Nodes) bulunur.
- Örnek: Binary Search Tree (İkili Arama Ağacı) - Veritabanı indekslerinde ve dosya sistemlerinde hızlı arama yapmak için kullanılır.
F. Hash Tabloları (Hash Tables)
- Verileri bir "Anahtar-Değer" (Key-Value) çifti şeklinde saklar.
- Bir anahtarı (örneğin bir kullanıcı adı) karmaşık bir fonksiyondan geçirerek benzersiz bir adrese dönüştürür.
- Örnek: Sözlükler (Python'daki dict, C#'daki Dictionary). Veriye erişim hızı neredeyse anlıktır.
3. Zaman Karmaşıklığı: Big O Notasyonu
Bir veri yapısını seçerken bakmanız gereken en önemli kriter Big O değeridir. Bu, veri miktarı arttıkça işlemin ne kadar yavaşlayacağını söyler:
- O(1): Sabit zaman (En hızlı - Dizide indekse erişim).
- O(log n): Logaritmik zaman (Hızlı - Ağaçlarda arama).
- O(n): Doğrusal zaman (Orta - Listede eleman arama).
Özet: Hangi Veri Yapısını Seçmelisin?
- Verilere sadece indeksle hızlıca ulaşmak istiyorsan: Dizi (Array).
- Sık sık ekleme ve silme yapıyorsan: Bağlı Liste (Linked List).
- Hiyerarşik bir düzen gerekiyorsa: Ağaç (Tree).
- Anahtar kelime ile anında erişim istiyorsan: Hash Table.
Kod Örnekleri:
Dizi (Array) Örneği:
pythondizi = [1, 2, 3, 4, 5] print(dizi[2]) # Çıktı: 3
Bağlı Liste (Linked List) Örneği:
pythonclass Node: def __init__(self, data): self.data = data self.next = None class LinkedList: def __init__(self): self.head = None def append(self, data): if not self.head: self.head = Node(data) else: current = self.head while current.next: current = current.next current.next = Node(data) def print_list(self): current = self.head while current: print(current.data) current = current.next linked_list = LinkedList() linked_list.append(1) linked_list.append(2) linked_list.append(3) linked_list.print_list() # Çıktı: 1, 2, 3
Yığın (Stack) Örneği:
pythonclass Stack: def __init__(self): self.stack = [] def push(self, data): self.stack.append(data) def pop(self): return self.stack.pop() stack = Stack() stack.push(1) stack.push(2) print(stack.pop()) # Çıktı: 2
Kuyruk (Queue) Örneği:
pythonclass Queue: def __init__(self): self.queue = [] def enqueue(self, data): self.queue.append(data) def dequeue(self): return self.queue.pop(0) queue = Queue() queue.enqueue(1) queue.enqueue(2) print(queue.dequeue()) # Çıktı: 1
Ağaç (Tree) Örneği:
pythonclass Node: def __init__(self, data): self.data = data self.left = None self.right = None class Tree: def __init__(self): self.root = None def insert(self, data): if not self.root: self.root = Node(data) else: self._insert(data, self.root) def _insert(self, data, node): if data < node.data: if node.left: self._insert(data, node.left) else: node.left = Node(data) else: if node.right: self._insert(data, node.right) else: node.right = Node(data) tree = Tree() tree.insert(5) tree.insert(3) tree.insert(7) tree.insert(2) tree.insert(4) tree.insert(6) tree.insert(8) print(tree.root.data) # Çıktı: 5 print(tree.root.left.data) # Çıktı: 3 print(tree.root.right.data) # Çıktı: 7
Hash Tablo (Hash Table) Örneği:
pythonclass HashTable: def __init__(self): self.size = 10 self.table = [[] for _ in range(self.size)] def hash_function(self, key): return hash(key) % self.size def insert(self, key, value): index = self.hash_function(key) for pair in self.table[index]: if pair[0] == key: pair[1] = value return self.table[index].append([key, value]) def get(self, key): index = self.hash_function(key) for pair in self.table[index]: if pair[0] == key: return pair[1] return None hash_table = HashTable() hash_table.insert("name", "John") hash_table.insert("age", 30) print(hash_table.get("name")) # Çıktı: John print(hash_table.get("age")) # Çıktı: 30
Konuyu Yanıtla
Markdown destekler · Alıntı, kod, liste kullanabilirsinizKonuyu yanıtlamak için giriş yapmalısınız.