Veri Yapıları ve Programlama

8 - Kuyruk İşlemleri ve Örnekleri

Emre Can Yılmaz

Ondokuz Mayıs Üniversitesi

2025

Geçen Haftanın Özeti

  • Kuyruk (Queue) Nedir? (FIFO Prensibi)
  • Kullanım Alanları
  • Temel Kavramlar (Enqueue, Dequeue, Peek, IsEmpty, IsFull, Front, Rear)
  • Kuyruk Türleri
  • Bağlı Liste ile Temel Yapı (struct test, head, tail)
  • enqueue (sonaEkle) İşlemi Örneği

Bağlı Liste Yapımız (Hatırlatma)

// Düğüm yapısı
struct Node {
    int veri;
    struct Node *sonraki;
};

struct Node *head = NULL; // Kuyruğun başı (çıkarılacak eleman)
struct Node *tail = NULL; // Kuyruğun sonu (eklenen eleman)

void enqueue(int sayi) {
    struct Node *yeniDugum = (struct Node *)malloc(sizeof(struct Node));
    if (yeniDugum == NULL) {
        printf("Hata: Bellek ayrılamadı!\n");
        return; // Bellek hatası durumunda fonksiyondan çık
    }
    yeniDugum->veri = sayi;
    yeniDugum->sonraki = NULL;

    if (tail == NULL) { // Kuyruk boşsa
        head = yeniDugum;
        tail = yeniDugum;
    } else { // Kuyrukta eleman varsa
        tail->sonraki = yeniDugum;
        tail = yeniDugum; // Tail'i güncelle
    }
    printf("%d kuyruğa eklendi.\n", sayi);
}

Dequeue İşlemi (Kuyruktan Eleman Çıkarma)

  • Kuyruğun başından (head) bir eleman çıkarır.
  • Çıkarılan elemanın verisini döndürür.
  • Kuyruk boşsa, özel bir değer döndürür (örn: INT_MIN) veya hata mesajı verir.
  • INT_MIN, limits.h kütüphanesinden gelir ve genellikle hata kodu olarak kullanılır.

Dequeue Fonksiyonu

int dequeue() {
    // 1. Kuyruk boş mu kontrol et
    if (head == NULL) {
        printf("Hata: Kuyruk boş!\n");
        // Boş kuyruktan eleman çıkarılamaz. Hata kodu olarak INT_MIN (limits.h) döndürebiliriz.
        return INT_MIN;
    }

    // 2. Geçici bir işaretçi ile head'i tut
    struct Node *temp = head;
    // 3. Çıkarılacak veriyi sakla
    int cikarilanVeri = temp->veri;

    // 4. Head'i bir sonraki elemana kaydır
    head = head->sonraki;

    // 5. Eğer head NULL olduysa (son eleman çıkarıldıysa), tail'i de NULL yap
    if (head == NULL) {
        tail = NULL;
    }

    // 6. Eski head düğümünün belleğini serbest bırak
    free(temp);

    // 7. Çıkarılan veriyi döndür
    printf("%d kuyruktan çıkarıldı.\n", cikarilanVeri);
    return cikarilanVeri;
}

Peek İşlemi (Öndeki Elemana Bakma)

  • Kuyruğun başındaki (head) elemanın verisini, elemanı çıkarmadan döndürür.
  • Kuyruk boşsa, özel bir değer döndürür (örn: INT_MIN) veya hata mesajı verir.
int peek() {
    // 1. Kuyruk boş mu kontrol et
    if (head == NULL) {
        printf("Hata: Kuyruk boş!\n");
        return INT_MIN; // Hata kodu
    }

    // 2. Head'in gösterdiği düğümün verisini döndür
    printf("Kuyruğun başındaki eleman: %d\n", head->veri);
    return head->veri;
}

IsEmpty İşlemi (Kuyruk Boş mu?)

  • Kuyruğun boş olup olmadığını kontrol eder.
  • Boşsa 1 (doğru), değilse 0 (yanlış) döndürür.
int isEmpty() {
    // Head NULL ise kuyruk boştur.
    if (head == NULL) {
        return 1; // Doğru (Boş)
    } else {
        return 0; // Yanlış (Boş değil)
    }
    // Kısa yolu: return (head == NULL);
}

IsFull İşlemi (Kuyruk Dolu mu?) - Bağlı Liste Durumu

  • Dinamik olarak bellek ayıran bağlı liste implementasyonlarında, kuyruk teorik olarak sadece sistem belleği dolduğunda “dolu” olur.
  • malloc başarısız olduğunda eleman eklenemez.
  • Bu nedenle, genellikle bağlı listeler için isFull fonksiyonu ya her zaman 0 (dolu değil) döndürür ya da implemente edilmez.
// Bağlı liste için genellikle gereksiz veya yanıltıcı olabilir.
int isFull() {
    // Dinamik bellekle çalıştığımız için "dolu" kavramı
    // bellek bitene kadar geçerli değildir.
    // Bu yüzden genellikle 0 döndürülür.
    return 0; // Dolu Değil
}

Örnek Kullanım (main fonksiyonu)

int main() {
    // Kuyruğun başlangıç durumu
    printf("Başlangıçta kuyruk boş mu? %s\n", isEmpty() ? "Evet" : "Hayır");

    // Eleman ekleyelim
    enqueue(10);
    enqueue(20);
    enqueue(30);

    printf("Kuyruk boş mu? %s\n", isEmpty() ? "Evet" : "Hayır");

    // Öndeki elemana bakalım
    peek();

    // Eleman çıkaralım
    dequeue();
    peek();

    dequeue();
    enqueue(40); // Kuyruk: 30, 40

    peek();
    dequeue();
    dequeue();
    // Kuyruk tekrar boşaldı
    printf("Son durumda kuyruk boş mu? %s\n", isEmpty() ? "Evet" : "Hayır");

    // Boş kuyruktan çıkarmayı deneyelim
    dequeue();

    return 0;
}

Örnek kod:

https://gist.github.com/ecylmz/dd3b7086fc80582ccce7b09034275574

Görselleştirme (Tekrar)

Kuyruk işlemlerinin adımlarını daha iyi anlamak için: https://lumos.emrecan.dev/queue

Alıştırma / Tartışma

  1. dequeue fonksiyonu boş kuyruk durumunda INT_MIN döndürmek yerine void olsa ve sadece hata mesajı bassa nasıl olurdu? Avantaj/Dezavantajları nelerdir?
  2. Dairesel Kuyruk (Circular Queue) dizi ile nasıl implemente edilir? Avantajları nelerdir?

Teşekkürler