Veri Yapıları ve Algoritma Temelleri: Python ile 10 Pratik Örnek
Algoritma ve Veri Yapıları
Veri Yapıları ve Algoritma Temelleri: Python ile 10 Pratik Örnek

Giriş
Veri yapıları ve algoritmalar, yazılım geliştirme ve algoritmik düşünmenin temelidir. Bu makalede Python ile 10 pratik örnek üzerinden sık kullanılan veri yapılarını ve temel algoritmaları inceliyoruz. Her örnekte kısa bir açıklama, çalıştırılabilir küçük kod parçası ve zaman karmaşıklığı notu bulacaksınız. Aşağıdaki kaynaklar rehberlik ve daha derin analiz için faydalıdır:
Daha derin teknik anlatımlar için bkz. Python ile Veri Yapıları ve Algoritma Analizi. Python temel bilgileri için kurslar: Python Temelleri ve Python Programlama Temel Seviye.
Bu makalede neler var?
Aşağıdaki 10 pratik örneği adım adım inceleyeceğiz:
- Python listeleri (dizi) — temel işlemler
- Stack (yığın) — LIFO
- Queue (kuyruk) — FIFO (collections.deque)
- Tek yönlü bağlı liste — özel sınıf
- İkili arama ağacı (BST) — ekleme ve dolaşma
- Heap / öncelik kuyruğu (heapq)
- Graf gösterimi ve BFS
- QuickSort — böl ve fethet
- Merge Sort — sabit en kötü durum
- Hash tablosu / frekans sayacı (dict)
1. Python listeleri (dizi) — temel işlemler
Açıklama: Python'un yerleşik listeleri dinamik diziler gibi davranır; ekleme, silme ve gezinme için kolay API sunar.
# Liste: ekleme, gezinme, arama nums = [3, 1, 4] nums.append(1) for i, v in enumerate(nums): print(i, v) if 4 in nums: print('Bulundu')
Zaman karmaşıklığı: append amortize O(1), arama (in) O(n). Bu tür analizler için kitap bölümleri faydalıdır (kaynak).
2. Stack (Yığın)
Açıklama: LIFO davranışı; Python listeleri ile hızlıca uygulanabilir.
stack = [] stack.append(10) # push stack.append(20) value = stack.pop() # pop
Zaman karmaşıklığı: push/pop O(1) (listenin sonundan yapılan işlemler).
3. Queue (Kuyruk) — collections.deque
Açıklama: FIFO kuyrukları için deque kullanın; popleft O(1) sağlar.
from collections import deque q = deque() q.append(1) # enqueue q.append(2) x = q.popleft() # dequeue
Not: Standart listede popleft O(n) olabilir; deque genellikle daha uygundur.
4. Tek yönlü bağlı liste (Singly Linked List)
Açıklama: Düğümler ile gösterilen zincir; araya ekleme başta O(1), ortada O(n) gibi davranır.
class Node: def __init__(self, val): self.val = val self.next = None class LinkedList: def __init__(self): self.head = None def insert_head(self, val): n = Node(val) n.next = self.head self.head = n def find(self, val): cur = self.head while cur: if cur.val == val: return True cur = cur.next return False
Zaman karmaşıklığı: insert_head O(1), find O(n). Bağlı liste örnekleri için uygulamalı alıştırmalar yapın.
5. İkili Arama Ağacı (BST)
Açıklama: Sıralı veriler için verimli arama/ekleme (dengeli olduğunda logaritmik zaman).
class BSTNode: def __init__(self, val): self.val = val self.left = None self.right = None def bst_insert(root, val): if root is None: return BSTNode(val) if val < root.val: root.left = bst_insert(root.left, val) else: root.right = bst_insert(root.right, val) return root def inorder(root): if root: inorder(root.left) print(root.val) inorder(root.right)
Zaman karmaşıklığı: Ortalama O(log n), en kötü O(n) (dengesiz ağaç). Daha fazla ağaç yapıları ve dengeli ağaçlar için kaynaklara göz atın.
6. Heap / Öncelik Kuyruğu (heapq)
Açıklama: En küçük/öncelikli öğeyi hızlı almak için heapq kullanılır.
import heapq h = [] heapq.heappush(h, (2, 'task2')) heapq.heappush(h, (1, 'task1')) priority, task = heapq.heappop(h)
Zaman karmaşıklığı: push/pop O(log n).
7. Graf: Adjacency List + BFS
Açıklama: Grafı komşuluk listesi ile temsil etmek, çoğu algoritma için uygundur; BFS genişlik öncelikli arama örneği:
from collections import deque graph = {'A':['B','C'], 'B':['A','D'], 'C':['A','D'], 'D':['B','C']} def bfs(start): q = deque([start]) visited = set([start]) order = [] while q: node = q.popleft() order.append(node) for neigh in graph.get(node, []): if neigh not in visited: visited.add(neigh) q.append(neigh) return order
Zaman karmaşıklığı: BFS/DFS: O(V + E) (düğümler + kenarlar).
8. QuickSort — böl ve fethet
Açıklama: Hızlı sıralama, ortalama performansı iyidir; basit uygulama:
def quicksort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr)//2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quicksort(left) + middle + quicksort(right)
Zaman karmaşıklığı: Ortalama O(n log n), en kötü O(n^2). Rastgele pivot veya üçlü median gibi tekniklerle kötü durumdan kaçınılabilir.
9. Merge Sort — sabit en kötü durum
Açıklama: Stabil, bölerek birleştiren sıralama; her durumda O(n log n) zaman alır.
def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr)//2 left = merge_sort(arr[:mid]) right = merge_sort(arr[mid:]) i = j = 0 res = [] while i < len(left) and j < len(right): if left[i] <= right[j]: res.append(left[i]); i += 1 else: res.append(right[j]); j += 1 res.extend(left[i:]); res.extend(right[j:]) return res
Zaman karmaşıklığı: O(n log n) her durumda; ekstra bellek kullanımı vardır.
10. Hash tablosu / Frekans sayacı (dict)
Açıklama: Python'un dict yapısı çoğu anahtar işlemini amortize O(1) sunar; örnek frekans sayacı:
def freq_count(items): counts = {} for x in items: counts[x] = counts.get(x, 0) + 1 return counts
Kullanım: metin analizi, sayma problemleri vb. Zaman karmaşıklığı: O(n) ortalama.
Zaman karmaşıklığına hızlı bakış
Aşağıda örnekler için sık kullanılan karmaşıklıklar özetlenmiştir:
| Yapı/Algoritma | Ortalama | En Kötü |
|---|---|---|
| Liste append | O(1) amortize | O(n) |
| Arama (liste) | O(n) | O(n) |
| Bağlı liste arama | O(n) | O(n) |
| BST arama (dengeli) | O(log n) | O(n) |
| Heap push/pop | O(log n) | O(log n) |
| QuickSort | O(n log n) | O(n^2) |
| Merge Sort | O(n log n) | O(n log n) |
| BFS/DFS | O(V + E) | O(V + E) |
Bu karmaşıklıklar ve analiz yaklaşımları için daha detaylı kuramsal bilgiler kaynak olarak kullanılabilir.
Nasıl çalıştırılır ve test edilir
- Bilgisayarınızda Python 3 kurulu olduğundan emin olun.
- Her örneği ayrı bir .py dosyasına yapıştırın veya bir Jupyter notebook hücresinde çalıştırın.
- Terminalden: python dosya_adi.py komutuyla çalıştırın.
- Performans ölçümleri için Python'ın timeit modülünü kullanın veya küçük/geniş veri kümeleriyle test yapın.
Pratik öneriler ve kontrol listesi
- Küçük örnekleri önce elle çalıştırın ve beklenen çıktıları doğrulayın.
- Veri setleri büyüdükçe zaman ve bellek kullanımını ölçün.
- Python'un yerleşik fonksiyonlarını (sorted, dict, heapq) tercih edin; genellikle optimize edilmişlerdir.
- Gerçek uygulamalarda giriş doğrulama, hata yönetimi ve test ekleyin.
Kaynaklar ve ileri okuma
Bu makalede temel kavramlar ve uygulamalar için başvurulan kaynaklar:
- Python ile Veri Yapıları ve Algoritma Analizi — detaylı kuramsal açıklamalar için.
- Python Temelleri — dilin temelleri ve yazım uygulamaları.
- Python Programlama Temel Seviye — başlangıç seviyesinde uygulamalı dersler.
Kapanış
Bu rehberdeki 10 örnek, "Algoritma ve Veri Yapıları" konularında pratik bir başlangıç sağlamayı amaçlar. Kodları değiştirerek kendi verilerinizle deneyin; analizler ve performans karşılaştırmaları öğrenmeyi derinleştirir. İleri seviye dengesiz ağaçlar, graf algoritmaları ve optimizasyonlar için belirtilen kaynaklardan devam edebilirsiniz.