#include <iostream>
#include <stdexcept>
#include <string>
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';
}
};
int main() {
try {
CircularQueue<int> queue(5);
// Добавление элементов
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
queue.print();
// Первый элемент
std::cout << "Front: " << queue.front() << '\n';
// Последний элемент
std::cout << "Back: " << queue.back() << '\n';
// Удаление элементов
queue.dequeue();
queue.dequeue();
queue.print();
// Проверка циклического использования массива
queue.enqueue(40);
queue.enqueue(50);
queue.enqueue(60);
queue.print();
// Размер и состояние
std::cout << "Size: " << queue.size() << '\n';
std::cout << "Capacity: " << queue.maxSize() << '\n';
std::cout << "Empty: "
<< (queue.isEmpty() ? "yes" : "no") << '\n';
std::cout << "Full: "
<< (queue.isFull() ? "yes" : "no") << '\n';
// Проверка исключения при переполнении
queue.enqueue(70);
// Очистка очереди
queue.clear();
std::cout << "After clear:\n";
queue.print();
} catch (const std::exception& error) {
std::cerr << "Error: " << error.what() << '\n';
return 1;
}
return 0;
}