Черга – це корисна структура даних у програмуванні. Уявіть чергу квитків поза кінозалом, де перша людина, що входить у чергу, є першою людиною, яка отримує квиток.
Черга слідує правилу «першим прийшов – першим обслужений» (First In First Out – FIFO) – елемент, який йде першим, – це елемент, який виходить першим.
Розглянемо рисунок. Оскільки 1 поміщена в чергу до 2, вона так само піде першою із черги. Це слідує правилу FIFO.
З погляду програмування, розміщення елемента у чергу (empty queue - порожня черга) називається "enqueue" (постановка у чергу), а видалення елемента з черги - "dequeue" (зняття черги).
Ми можемо реалізувати чергу будь-якою мовою програмування, такою як C, C++, Java, Python або C#, майже з однаковою специфікацією.
Технічні характеристики черги
Черга - це об'єкт або, конкретніше, абстрактна структура даних (ADT), яка дозволяє виконувати наступні операції:
- Enqueue: додати елемент до кінця черги;
- Dequeue: видалити елемент із початку черги;
- IsEmpty: перевірити, чи порожня черга;
- IsFull: перевірте, чи заповнена черга;
- Peek: отримати значення початку черги, не видаляючи його.
Як працює черга
Операції з чергами працюють таким чином:
- Два вказівники, звані FRONT та REAR, використовуються для відстеження першого та останнього елементів у черзі.
- При ініціалізації черги ми встановлюємо значення FRONT та REAR рівним -1.
- При додаванні елемента ми збільшуємо значення індексу REAR і поміщаємо новий елемент у положення, яке вказує REAR.
- При видаленні елемента з черги ми повертаємо значення, яке вказує FRONT, і збільшуємо індекс FRONT.
- Перед постановкою на чергу ми перевіряємо, чи заповнена черга.
- Перед зняттям черги ми перевіряємо, чи порожня черга.
- При ініціалізації першого елемента ми встановлюємо значення FRONT 0.
- При видаленні останнього елемента ми скидаємо значення FRONT і REAR -1.
Реалізація черги мовою програмування
Найбільш поширена реалізація черги використовує масиви, але також черга може бути з використанням списків.
Реалізація з використанням C-програмування
#include<stdio.h> #define SIZE 5 void enQueue(int); void deQueue(); void display(); int items[SIZE], front = -1, rear = -1; int main() { //deQueue невозможно в пустой очереди deQueue(); //enQueue 5 elements enQueue(1); enQueue(2); enQueue(3); enQueue(4); enQueue(5); //6-й элемент не может быть добавлен в очередь, потому что очередь заполнена enQueue(6); display(); //deQueue удаляет элемент, введенный первым, т.е. 1 deQueue(); //Теперь у нас всего 4 элемента display(); return 0; } void enQueue(int value){ if(rear == SIZE-1) printf("\nQueue is Full!!"); else { if(front == -1) front = 0; rear++; items[rear] = value; printf("\nInserted -> %d", value); } } void deQueue(){ if(front == -1) printf("\nQueue is Empty!!"); else{ printf("\nDeleted : %d", items[front]); front++; if(front > rear) front = rear = -1; } } void display(){ if(rear == -1) printf("\nQueue is Empty!!!"); else{ int i; printf("\nQueue elements are:\n"); for(i=front; i<=rear; i++) printf("%d\t",items[i]); } }
Коли ви запускаєте цю програму, ви отримуєте таке:
Queue is Empty!! Inserted -> 1 Inserted -> 2 Inserted -> 3 Inserted -> 4 Inserted -> 5 Queue is Full!! Queue elements are: 1 2 3 4 5 Deleted : 1 Queue elements are: 2 3 4 5
Реалізація з використанням програмування на C++
#include <iostream> #define SIZE 5 using namespace std; class Queue { private: int items[SIZE], front, rear; public: Queue(){ front = -1; rear = -1; } bool isFull(){ if(front == 0 && rear == SIZE - 1){ return true; } return false; } bool isEmpty(){ if(front == -1) return true; else return false; } void enQueue(int element){ if(isFull()){ cout << "Queue is full"; } else { if(front == -1) front = 0; rear++; items[rear] = element; cout << endl << "Inserted " << element << endl; } } int deQueue(){ int element; if(isEmpty()){ cout << "Queue is empty" << endl; return(-1); } else { element = items[front]; if(front >= rear){ front = -1; rear = -1; } /* В Q есть только один элемент, поэтому мы удаляем очередь после удаления. */ else { front++; } cout << endl << "Deleted -> " << element << endl; return(element); } } void display() { /* Функция для отображения элементов очереди */ int i; if(isEmpty()) { cout << endl << "Empty Queue" << endl; } else { cout << endl << "Front -> " << front; cout << endl << "Items -> "; for(i=front; i<=rear; i++) cout << items[i] << ""\t"; cout << endl << "Rear -> " << rear << endl; } } }; int main() { Queue q; //deQueue невозможно в пустой очереди q.deQueue(); //enQueue 5 элементов q.enQueue(1); q.enQueue(2); q.enQueue(3); q.enQueue(4); q.enQueue(5); //6-й элемент не может быть добавлен в очередь, потому что очередь заполнена q.enQueue(6); q.display(); //deQueue удаляет элемент, введенный первым, т.е. 1 q.deQueue(); //Теперь у нас всего 4 элемента q.display(); return 0; }
Після запуску ми отримаємо:
Queue is empty Inserted 1 Inserted 2 Inserted 3 Inserted 4 Inserted 5 Queue is full Front -> 0 Items -> 1 2 3 4 5 Rear -> 4 Deleted -> 1 Front -> 1 Items -> 2 3 4 5 Rear -> 4
Обмеження цієї реалізації
Як ви можете бачити на зображенні нижче, через деякий час після додавання в чергу та видалення з черги розмір черги був зменшений.
Індекси 0 та 1 можуть використовуватися тільки після скидання черги, коли всі елементи видалені.
Змінюючи код для черги, ми можемо використовувати простір шляхом реалізації модифікованої черги, яка називається циклічною чергою.