Algoritmalar ve Veri Yapıları: Yeni Başlayanlar İçin 7 Temel Örnek

Algoritma ve Veri Yapıları

Algoritmalar ve Veri Yapıları: Yeni Başlayanlar İçin 7 Temel Örnek

Bu rehber, yeni başlayanlar için 7 temel veri yapısı ve algoritmayı (list, stack, queue, linear/binary search, bubble/merge sort) kısa Python örnekleriyle açıklar ve Big O düşünme biçimini pratikleştirir.
Algoritmalar ve Veri Yapıları: Yeni Başlayanlar İçin 7 Temel Örnek

Algoritmalar ve veri yapıları, yazılım geliştirmenin “mutfak” kısmıdır: Bir problemi hangi veriyi nasıl tutarak ve hangi adımlarla çözeceğinizi belirler. Bu yazı, adım adım programlama öğrenme hedefiyle, yeni başlayanların en sık karşılaşacağı 7 temel örneği kısa Python kodları ile ele alır.

Not: Buradaki örnekler eğitim amaçlıdır. Gerçek projelerde çoğu zaman Python’un yerleşik araçları (ör. sorted()) daha doğru bir başlangıçtır. Yine de bu temel örnekleri anlamak, “neden böyle çalışıyor?” sorusunu cevaplamanıza yardımcı olur.


Ön bilgi: Big O neyi anlatır?

Algoritmaları karşılaştırırken “ne kadar hızlı?” sorusu tek başına yeterli değildir; girdi büyüdükçe işin nasıl büyüdüğünü düşünmek gerekir. Big O (O()) gösterimi, bu büyüme oranını ifade etmek için kullanılan yaygın bir çerçevedir. Ayrıca en iyi/ortalama/en kötü durum ayrımı pratikte önemlidir. Bu yaklaşımın temelleri için MIT’nin Big O anlatımına göz atabilirsiniz: MIT OCW 6.0001 Big O ders notu.

Bu yazıda Big O’yu “ezberlenecek bir tablo” gibi değil, adım sayısının girdiyle nasıl arttığını okumaya yarayan bir “gözlük” gibi kullanacağız.


1) Veri yapısı: Python list ile “dinamik dizi” düşünmek

Python’da list, yeni başlayanların en çok kullandığı veri yapısıdır. Yerleşik veri tiplerinin temelleri için Python resmi tutorial’ı iyi bir referanstır: The Python Tutorial (Python 3.11). List’lerle temel amaç, veriyi sırayla tutmak ve üzerinde dolaşmaktır.

Ne zaman iş görür?

  • Sırayla saklanan veriler (puanlar, isimler, log satırları).
  • Üzerinde gezme (iteration) ve filtreleme.
  • Basit arama ve sıralama denemeleri.

Kısa örnek (listeyi filtreleme)

Aşağıdaki kod, bir listeden belirli bir koşulu sağlayan elemanları seçer. Not: HTML kısıtları nedeniyle kod biçimlendirmesi satır satır sadeleştirildi; örneklerin tamamı Python 3 ile çalıştırılabilir.

Python 3
# Python 3
nums = [3, 10, 2, 8, 7]

evens = [x for x in nums if x % 2 == 0]
print(evens) # [10, 2, 8]

Pratik ipucu

Yeni başlayanlar için iyi bir alışkanlık: Bir probleme başlarken önce “Veriyi nasıl tutacağım?” sorusunu cevaplayın. Çoğu giriş seviyesi senaryoda list, dict ve set gibi yerleşik yapılar yeterlidir. Bu yaklaşımı ve temel kullanım biçimlerini Python dokümantasyonu üzerinden takip edebilirsiniz: Python Tutorial.

Mini not: “Listeler ve ağaçlar” bağlantısı

Python’da “tree” (ağaç) için yerleşik bir tip yoktur; genelde sınıflarla düğüm (node) oluşturulur. Ağaçları bu yazıda ayrı bir örnek olarak saymayacağız ama “hiyerarşi” içeren verilerde (kategori ağacı, dosya sistemi gibi) list’ten farklı bir model gerektiğini bilmek önemlidir.


2) Veri yapısı: Stack (yığın) — LIFO mantığı

Stack, “son giren ilk çıkar” (LIFO) mantığıyla çalışır. Python’da çoğu giriş senaryosunda stack’i bir list ile basitçe modelleyebilirsiniz.

Ne zaman kullanılır?

  • Geri alma (undo) geçmişi.
  • Parantez dengeleme gibi denetimler.
  • Derinlik öncelikli gezme (DFS) gibi örneklerde “son eklenenin işlenmesi” mantığı.

Kısa örnek (push/pop)

Python 3
# Python 3
stack = []

# push
stack.append("A")
stack.append("B")
stack.append("C")

# pop
last = stack.pop()
print(last) # C
print(stack) # ['A', 'B']

Kontrol listesi: Stack uygularken, yalnızca “sona ekle” ve “sondan çıkar” işlemlerini kullanmaya çalışın. Böylece yığının mantığını kod üzerinden net görürsünüz.


3) Veri yapısı: Queue (kuyruk) — FIFO ve collections.deque

Queue, “ilk giren ilk çıkar” (FIFO) mantığıdır. Bir list ile de yapılabilir; ancak baştan eleman çıkarmak için list kullanmak pratikte verimsiz olabilir. Bu nedenle Python, kuyruk benzeri senaryolarda collections.deque kullanımını önerir. Resmi dokümantasyona göre deque, iki uçtan ekleme/çıkarma işlemlerinde yaklaşık O(1) performans sunar: collections — Container datatypes.

Kısa örnek (deque ile FIFO)

Python 3
# Python 3
from collections import deque

q = deque()
q.append("task-1")
q.append("task-2")
q.append("task-3")

first = q.popleft()
print(first) # task-1
print(q) # deque(['task-2', 'task-3'])

Ne zaman kullanılır?

  • Sıra tabanlı işleme (iş kuyruğu, mesaj kuyruğu).
  • Kaynak sınırlı “bekleme listeleri”.
  • Kaydırmalı pencere (sliding window) problemleri.

4) Algoritma: Linear Search (doğrusal arama)

Linear search, bir listede aranan değeri baştan sona kontrol ederek bulmaya çalışır. Mantığı basittir ve yeni başlayanlar için iyi bir ilk “arama algoritması” örneğidir.

Big O’yu sezgisel okumak

Aradığınız değer en sonda olabilir; o zaman tüm elemanlara bakmanız gerekir. Bu nedenle iş miktarı, liste boyutu büyüdükçe “yaklaşık lineer” büyür. Bu tür büyüme, Big O dilinde genelde O(n) olarak ifade edilir (Big O kavramı için: MIT OCW notu).

Kısa örnek (index döndürme)

Python 3
# Python 3
def linear_search(arr, target):
    for i, x in enumerate(arr):
        if x == target:
            return i
    return -1

nums = [4, 9, 1, 7]
print(linear_search(nums, 7)) # 3
print(linear_search(nums, 99)) # -1

Ne zaman tercih edilir?

  • Liste çok küçükse.
  • Veri sıralı değilse ve sıralamak istemiyorsanız.
  • Tek seferlik arama yapıyorsanız.

5) Algoritma: Binary Search (ikili arama)

Binary search, yalnızca sıralı bir dizide çalışır. Fikir şudur: Ortadaki elemanı kontrol eder, hedef daha küçükse sol yarıya, büyükse sağ yarıya geçersiniz. Her adımda arama alanı kabaca yarıya indiği için adım sayısı “logaritmik” büyür (Big O bakışı için: MIT OCW Big O notu).

Kısa örnek (iteratif binary search)

Python 3
# Python 3
def binary_search(sorted_arr, target):
    lo, hi = 0, len(sorted_arr) - 1
    while lo <= hi:
        mid = (lo + hi) // 2
        if sorted_arr[mid] == target:
            return mid
        if sorted_arr[mid] < target:
            lo = mid + 1
        else:
            hi = mid - 1
    return -1

arr = [1, 3, 4, 7, 10, 12]
print(binary_search(arr, 10)) # 4
print(binary_search(arr, 2)) # -1

Sık yapılan hatalar

  • Liste sıralı değilken binary search denemek.
  • lo/hi güncellemelerini yanlış yapmak (sonsuz döngü riski).
  • “Bulunamadı” durumunu (-1 gibi) net tanımlamamak.

6) Sıralama algoritması: Bubble Sort (öğretici klasik)

Bubble sort, komşu elemanları karşılaştırıp yer değiştirerek listeyi yavaş yavaş sıralar. Eğitim için anlaşılırdır; ancak küçük örnekler dışında genelde tercih edilmez. MIT’nin sıralama algoritmalarına giriş içeriği, bubble gibi basit yöntemlerin öğretici değerini ve tipik olarak daha yüksek maliyetli olduğunu açıklar: Sorting Algorithms | MIT BLOSSOMS.

Karmaşıklık (genel çerçeve)

Bubble sort’un ortalama/en kötü durum performansı genellikle O(n^2) olarak verilir; bu yüzden veri büyüdükçe hızla yavaşlar. Bu kıyas, giriş seviyesinde “neden daha iyi sıralamalar var?” sorusunu anlamak için faydalıdır (bkz. MIT BLOSSOMS).

Kısa örnek (bubble sort)

Python 3
# Python 3
def bubble_sort(arr):
    a = arr[:] # kopya
    n = len(a)
    for i in range(n):
        swapped = False
        for j in range(0, n - 1 - i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
                swapped = True
        if not swapped:
            break
    return a

print(bubble_sort([3, 2, 5, 1])) # [1, 2, 3, 5]

Mini test önerileri

  • Boş liste: []
  • Tek eleman: [7]
  • Zaten sıralı: [1, 2, 3]
  • Ters sıralı: [3, 2, 1]
  • Tekrarlı değer: [2, 1, 2, 1]

7) Sıralama algoritması: Merge Sort (böl ve yönet)

Merge sort, listeyi ikiye bölüp alt parçaları sıraladıktan sonra birleştirerek ilerler. Karşılaştırma temelli verimli sıralamalar arasında klasik bir örnektir. MIT’nin sıralama anlatımları, merge sort gibi yöntemlerin tipik büyümesinin O(n log n) seviyesinde olduğunu ve pratikte bubble gibi basit yöntemlere göre daha iyi ölçeklendiğini vurgular: MIT BLOSSOMS.

Kısa örnek (merge sort)

Python 3
# Python 3
def merge_sort(arr):
    if len(arr) <= 1:
        return arr[:]
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])
    right = merge_sort(arr[mid:])
    return merge(left, right)

def merge(left, right):
    out = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            out.append(left[i])
            i += 1
        else:
            out.append(right[j])
            j += 1
    out.extend(left[i:])
    out.extend(right[j:])
    return out

print(merge_sort([3, 2, 5, 1])) # [1, 2, 3, 5]

Ne zaman düşünülür?

  • Veri büyüdükçe performansın korunmasını istiyorsanız.
  • “Böl ve yönet” yaklaşımını kavramak istiyorsanız.

Quicksort hakkında kısa not

Bir başka klasik yöntem olan quicksort, çoğu durumda hızlı olabilir; ancak Big O bakışında “en kötü durum” analizi önemlidir. Örneğin quicksort için en kötü durumda O(n^2) senaryoları tartışılır. En kötü/ortalama durum ayrımı gibi kavramlar, Big O’nun pratikte neden önemli olduğuna iyi bir örnektir (bkz. MIT OCW ve sıralama genel çerçevesi için MIT BLOSSOMS).


Hızlı karşılaştırma tablosu (öğrenme amaçlı)

Aşağıdaki tablo, örnekler arası farkı “hangi durumda ne iş görür?” perspektifiyle özetler. Big O notasyonu ve durum ayrımları için MIT kaynağı iyi bir çerçeve sunar: MIT OCW.

Konu Ön koşul Ne öğrenirsiniz? Not
Linear search Yok Sade arama mantığı Tek tek kontrol
Binary search Dizi sıralı olmalı Alanı yarıya indirerek arama Sıralama maliyetini unutmayın
Bubble sort Yok Karşılaştırmalı sıralama fikri Genelde O(n^2) olarak öğretilir (MIT BLOSSOMS)
Merge sort Yok Böl ve yönet yaklaşımı Genelde O(n log n) ölçeğinde anlatılır (MIT BLOSSOMS)
Queue (deque) collections FIFO modelleme İki uçtan ekleme/çıkarma için ~O(1) (Python docs)

Bir sonraki adım: Bu 7 örneği nasıl pekiştirirsiniz?

  • 1 gün 1 örnek yaklaşımı: Her gün bir veri yapısı/algoritma seçip 3 farklı test girdisiyle çalıştırın.
  • Problemi eşleştirme: “Veri sıralı mı?”, “Sırayla mı işleyeceğim?”, “Geri almak (undo) var mı?” gibi sorularla stack/queue/search/sort arasında seçim yapın.
  • Yerleşik araçları okuyun: Python’un yerleşik tiplerini ve koleksiyonlarını düzenli olarak resmi dokümantasyondan kontrol edin: Python Tutorial, collections.
  • “Ağaçlar”a geçiş: Hiyerarşik veri modellemeye ihtiyacınız olduğunda node tabanlı ağaç yapıları ve traversal (DFS/BFS) örneklerine geçin.

Bu temel seti oturttuğunuzda, daha ileri seviyede grafikler, öncelik kuyrukları, hashing stratejileri ve gerçek dünya performans ölçümü (profiling) gibi konular çok daha anlaşılır hale gelir.