logo

C'deki kuyruk

Bilgisayar biliminde kuyruk, bileşenlerin 'ilk giren ilk çıkar' (FIFO) ilkesine göre bir uca yerleştirildiği ve diğer uçtan çıkarıldığı doğrusal bir veri yapısıdır. Bu veri yapısı bir eylem sırasını kontrol etmek veya verileri depolamak için kullanılabilir. C, diziler veya bağlantılı listeler biçiminde birleştirilmiş kuyruk özelliğine sahip bir bilgisayar dilidir.

Özellikler:

  • Kuyruk, bir dizi veya bağlantılı listeyle oluşturulabilen bir tür doğrusal veri yapısıdır.
  • Öğeler önden çıkarılırken kuyruğun arkasına taşınır.
  • Enqueue (arkaya bir öğe ekleyin) ve dequeue (önden bir öğeyi kaldırın) iki kuyruk işlemidir.
  • Öğeler sık ​​sık eklenip kaldırıldığında, belleğin israfını önlemek için dairesel bir kuyruk şeklinde bir kuyruk oluşturulabilir.

Diziyi Kullanma:

C'de bir dizi kullanarak bir kuyruk uygulamak için, önce kuyruğun maksimum boyutunu tanımlayın ve bu boyutta bir dizi bildirin. Ön ve arka tamsayılar sırasıyla 1'e ayarlandı. Ön değişken kuyruğun ön elemanını, arka değişken ise arka elemanı temsil eder.

Yeni elemanı kuyruğun son pozisyonuna itmeden önce back değişkenini 1 arttırmamız gerekiyor. Kuyruk artık doludur ve arka pozisyon kuyruğun maksimum kapasitesine ulaştığında başka hiçbir ek eleman eklenemez. Kuyruğun önüne bir öğe ekliyoruz ve ön değişkeni yalnızca bir öğeyi kuyruktan çıkarmak için bir artırıyoruz. Ön ve arka konumlar eşitse ve daha fazla bileşen silinemiyorsa kuyruğun boş olduğunu söyleyebiliriz.

Aşağıda C dilinde yazılmış ve bir diziyi kullanan bir kuyruğun örneği verilmiştir:

C Programlama Dili:

 #define MAX_SIZE 100 int queue[MAX_SIZE]; int front = -1; int rear = -1; void enqueue(int element) { if (rear == MAX_SIZE - 1) { printf('Queue is full'); return; } if (front == -1) { front = 0; } rear++; queue[rear] = element; } int dequeue() { if (front == -1 || front > rear) { printf('Queue is empty'); return -1; } int element = queue[front]; front++; return element; } int main() { enqueue(10); enqueue(20); enqueue(30); printf('%d ', dequeue()); printf('%d ', dequeue()); printf('%d ', dequeue()); printf('%d ', dequeue()); return 0; } 

Kodun çıktısı şöyle olacaktır:

Çıktı:

jvm
 10 20 30 Queue is empty-1 

Açıklama:

  1. İlk olarak, 10, 20 ve 30 numaralı üç öğeyi kuyruğa alıyoruz.
  2. Daha sonra kuyruğun ön elemanı olan 10'u ayırıp yazdırıyoruz.
  3. Daha sonra kuyruğun ön elemanı olan 20'yi tekrar kaldırıyoruz ve yazdırıyoruz.
  4. Daha sonra kuyruğun ön elemanı olan 30'u tekrar kaldırıyoruz ve yazdırıyoruz.
  5. Son olarak, 'Kuyruk boş' sonucunu veren ve -1 döndüren boş bir kuyruktan bir kuyruk oluşturuyoruz.

Bağlantılı Listeyi Kullanma:

C programlama dilinde kuyruk oluşturmaya yönelik başka bir alternatif yaklaşım, bağlantılı liste kullanmaktır. Kuyruktaki düğümlerin her biri, bu yöntem kullanılarak, eleman değerini içeren bir düğüm ve kuyrukta bir sonraki düğüme işaret eden bir işaretçi tarafından ifade edilir. Sıradaki ilk ve son düğümleri takip etmek için sırasıyla ön ve arka işaretçiler kullanılır.

Kuyruğa bir eleman eklemek için eleman değeriyle yeni bir düğüm kuruyoruz ve bir sonraki işaretçisini NULL olarak ayarlıyoruz. Yeni düğüme eğer sıra boşsa ön ve arka işaretçileri ayarlıyoruz. Değilse, arka işaretçiyi güncelleriz ve eski arka düğümün bir sonraki işaretçisini yeni düğümü işaret edecek şekilde ayarlarız.

Bir kuyruktan bir düğüm silinirken, önce önceki düğüm silinir, ardından ön işaretçi kuyruktaki bir sonraki düğüme güncellenir ve son olarak kaldırılan düğümün kapladığı bellek serbest bırakılır. Ön işaretçi kaldırıldıktan sonra NULL ise kuyruk boştur.

Aşağıda, bağlantılı bir liste kullanılarak C'de uygulanan bir kuyruk örneği verilmiştir:

C Programlama Dili:

 #include #include struct Node { int data; struct Node* next; }; struct Node* front = NULL; struct Node* rear = NULL; void enqueue(int element) { struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); new_node->data = element; new_node->next = NULL; if (front == NULL && rear == NULL) { front = rear = new_node; return; } rear->next = new_node; rear = new_node; } int dequeue() { if (front == NULL) { printf('Queue is empty'); return -1; } struct Node* temp = front; int element = temp->data; if (front == rear) { front = rear = NULL; } else { front = front->next; } free(temp); return element; } int main() { enqueue(10); enqueue(20); enqueue(30); printf('%d ', dequeue()); printf('%d ', dequeue()); printf('%d ', dequeue()); printf('%d ', dequeue()); return 0; } 

Kodun çıktısı şöyle olacaktır:

Çıktı:

 10 20 30 Queue is empty-1 

Açıklama:

  1. İlk olarak, 10, 20 ve 30 numaralı üç öğeyi kuyruğa alıyoruz.
  2. Daha sonra kuyruğun ön elemanı olan 10'u ayırıp yazdırıyoruz.
  3. Daha sonra kuyruğun ön elemanı olan 20'yi tekrar kaldırıyoruz ve yazdırıyoruz.
  4. Daha sonra kuyruğun ön elemanı olan 30'u tekrar kaldırıyoruz ve yazdırıyoruz.
  5. Son olarak, 'Kuyruk boş' mesajını yazdıran ve -1 döndüren boş kuyruktan ayrılmaya çalışıyoruz.

Avantajları:

  • Kuyruklar, özellikle kapsamlı arama ve görev planlama gibi öğelerin kesin bir sırayla işlenmesini gerektiren algoritmaların uygulanması için kullanışlıdır.
  • Kuyruk işlemlerinin O(1) zaman karmaşıklığı olduğundan, çok büyük kuyruklarda bile hızlı bir şekilde yürütülebilirler.
  • Kuyruklar özellikle esnektir çünkü bir dizi veya bağlantılı liste kullanılarak basit bir şekilde uygulanabilmektedirler.

Dezavantajları:

  • Bir yığının aksine bir kuyruk tek bir işaretçiyle oluşturulamaz, bu da kuyruk uygulamasını biraz daha karmaşık hale getirir.
  • Kuyruk bir dizi olarak oluşturulmuşsa, çok fazla öğe eklenirse kısa sürede dolabilir, bu da performans sorunlarına veya muhtemelen bir çökmeye neden olabilir.
  • Kuyruğu uygulamak için bağlantılı bir liste kullanıldığında, her düğümün bellek yükü, özellikle küçük öğeler için önemli olabilir.

Çözüm:

Önemli bir veri yapısı olan kuyrukları kullanan uygulamalar arasında işletim sistemleri, ağ iletişimi ve oyunlar yer alır. Bir dizi veya bağlantılı liste kullanılarak oluşturulmaları basit olduğundan, öğeleri belirli bir sırayla ele alması gereken algoritmalar için idealdirler. Ancak kuyrukların, belirli bir uygulama için veri yapısı seçerken dikkate alınması gereken bellek tüketimi ve uygulama karmaşıklığı gibi dezavantajları vardır.