#include <iostream>
#include <stdexcept>
#include <cstddef>
template <typename T>
class CircularQueue {
private:
T* data; // Массив для хранения элементов
std::size_t capacity; // Максимальная вместимость
std::size_t frontIndex; // Индекс первого элемента
std::size_t rearIndex; // Индекс следующей свободной позиции
std::size_t count; // Текущее количество элементов
public:
// Конструктор
explicit CircularQueue(std::size_t capacity)
: data(nullptr),
capacity(capacity),
frontIndex(0),
rearIndex(0),
count(0) {
if (capacity == 0) {
throw std::invalid_argument(
"Capacity must be greater than 0"
);
}
data = new T[capacity];
}
// Деструктор
~CircularQueue() {
delete[] data;
}
// Запрещаем копирование, чтобы избежать двойного освобождения памяти
CircularQueue(const CircularQueue&) = delete;
CircularQueue& operator=(const CircularQueue&) = delete;
// Проверка на пустоту
bool isEmpty() const noexcept {
return count == 0;
}
// Проверка на заполненность
bool isFull() const noexcept {
return count == capacity;
}
// Текущий размер очереди
std::size_t size() const noexcept {
return count;
}
// Максимальный размер очереди
std::size_t maxSize() const noexcept {
return capacity;
}
// Добавление элемента в конец очереди
void enqueue(const T& value) {
if (isFull()) {
throw std::overflow_error("Queue is full");
}
data[rearIndex] = value;
// Циклический переход к следующей позиции
rearIndex = (rearIndex + 1) % capacity;
++count;
}
// Удаление элемента из начала очереди
void dequeue() {
if (isEmpty()) {
throw std::underflow_error("Queue is empty");
}
// Просто перемещаем индекс начала.
// Сами элементы массива не сдвигаются.
frontIndex = (frontIndex + 1) % capacity;
--count;
}
// Получение первого элемента
T& front() {
if (isEmpty()) {
throw std::underflow_error("Queue is empty");
}
return data[frontIndex];
}
const T& front() const {
if (isEmpty()) {
throw std::underflow_error("Queue is empty");
}
return data[frontIndex];
}
// Получение последнего элемента
T& back() {
if (isEmpty()) {
throw std::underflow_error("Queue is empty");
}
std::size_t index =
(rearIndex + capacity - 1) % capacity;
return data[index];
}
const T& back() const {
if (isEmpty()) {
throw std::underflow_error("Queue is empty");
}
std::size_t index =
(rearIndex + capacity - 1) % capacity;
return data[index];
}
// Очистка очереди
void clear() noexcept {
frontIndex = 0;
rearIndex = 0;
count = 0;
}
// Вывод содержимого очереди
void print() const {
if (isEmpty()) {
std::cout << "Queue: empty\n";
return;
}
std::cout << "Queue: ";
for (std::size_t i = 0; i < count; ++i) {
std::size_t index =
(frontIndex + i) % capacity;
std::cout << data[index];
if (i + 1 < count) {
std::cout << " ";
}
}
std::cout << '\n';
}
// Вывод внутреннего состояния для демонстрации
// работы циклического массива
void printState() const {
std::cout << "frontIndex = " << frontIndex
<< ", rearIndex = " << rearIndex
<< ", size = " << count
<< ", capacity = " << capacity
<< '\n';
}
};
int main() {
try {
// Создание циклической очереди вместимостью 5 элементов
CircularQueue<int> queue(5);
std::cout << "=== 1. Initial state ===\n";
queue.print();
queue.printState();
// ---------------------------------------------------------
// 2. Добавление элементов
// ---------------------------------------------------------
std::cout << "\n=== 2. Enqueue ===\n";
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.print();
queue.printState();
// ---------------------------------------------------------
// 3. Просмотр первого и последнего элемента
// ---------------------------------------------------------
std::cout << "\n=== 3. Front / Back ===\n";
std::cout << "Front: " << queue.front() << '\n';
std::cout << "Back: " << queue.back() << '\n';
// ---------------------------------------------------------
// 4. Удаление элементов
// ---------------------------------------------------------
std::cout << "\n=== 4. Dequeue ===\n";
queue.dequeue();
std::cout << "After dequeue:\n";
queue.print();
queue.printState();
// ---------------------------------------------------------
// 5. Демонстрация циклического использования массива
// ---------------------------------------------------------
std::cout << "\n=== 5. Circular array test ===\n";
queue.enqueue(40);
queue.enqueue(50);
queue.enqueue(60);
queue.print();
queue.printState();
/*
* После удаления первого элемента освободилась первая
* позиция массива. Благодаря оператору %
* rearIndex продолжает движение циклически и использует
* освободившееся место, не сдвигая остальные элементы.
*/
// ---------------------------------------------------------
// 6. Заполнение очереди до максимальной вместимости
// ---------------------------------------------------------
std::cout << "\n=== 6. Full queue test ===\n";
// Сейчас в очереди 5 элементов
queue.print();
std::cout << "Is full: "
<< (queue.isFull() ? "yes" : "no")
<< '\n';
// ---------------------------------------------------------
// 7. Проверка переполнения
// ---------------------------------------------------------
std::cout << "\n=== 7. Overflow test ===\n";
try {
queue.enqueue(70);
}
catch (const std::overflow_error& error) {
std::cout << "Overflow handled correctly: "
<< error.what() << '\n';
}
// ---------------------------------------------------------
// 8. Проверка удаления и повторного циклического добавления
// ---------------------------------------------------------
std::cout << "\n=== 8. Reuse freed position ===\n";
queue.dequeue();
queue.dequeue();
queue.print();
queue.printState();
// Добавляем элементы в освободившиеся позиции
queue.enqueue(70);
queue.enqueue(80);
queue.print();
queue.printState();
// ---------------------------------------------------------
// 9. Проверка размера очереди
// ---------------------------------------------------------
std::cout << "\n=== 9. Size test ===\n";
std::cout << "Current size: "
<< queue.size() << '\n';
std::cout << "Maximum size: "
<< queue.maxSize() << '\n';
// ---------------------------------------------------------
// 10. Очистка очереди
// ---------------------------------------------------------
std::cout << "\n=== 10. Clear ===\n";
queue.clear();
queue.print();
queue.printState();
std::cout << "Is empty: "
<< (queue.isEmpty() ? "yes" : "no")
<< '\n';
// ---------------------------------------------------------
// 11. Проверка удаления из пустой очереди
// ---------------------------------------------------------
std::cout << "\n=== 11. Underflow test ===\n";
try {
queue.dequeue();
}
catch (const std::underflow_error& error) {
std::cout << "Underflow handled correctly: "
<< error.what() << '\n';
}
// ---------------------------------------------------------
// 12. Проверка добавления после очистки
// ---------------------------------------------------------
std::cout << "\n=== 12. Reuse after clear ===\n";
queue.enqueue(100);
queue.enqueue(200);
queue.print();
std::cout << "Front: " << queue.front() << '\n';
std::cout << "Back: " << queue.back() << '\n';
std::cout << "\n=== All tests completed successfully ===\n";
}
catch (const std::invalid_argument& error) {
std::cerr << "Invalid argument: "
<< error.what() << '\n';
return 1;
}
catch (const std::exception& error) {
std::cerr << "Unexpected error: "
<< error.what() << '\n';
return 1;
}
return 0;
}