Алгоритмы и структуры данных на C++: практическое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Алгоритмы и структуры данных на C++: от теории к практике

Освоение алгоритмов и структур данных — ключевой этап в становлении профессионального разработчика. Без глубокого понимания того, как эффективно организовывать и обрабатывать данные, невозможно создавать производительные и масштабируемые приложения. C++ предоставляет уникальные возможности для низкоуровневой работы с памятью и высокой производительности, что делает его идеальным языком для изучения этой темы.

В этой статье мы рассмотрим фундаментальные алгоритмы и структуры данных на C++ с практическими примерами кода, которые вы сможете сразу применить в своих проектах. Мы не будем углубляться в абстрактные математические выкладки — наш фокус на реальной реализации и понимании принципов работы.

1. Динамические массивы и работа с памятью

Начнем с основ — динамических массивов. В отличие от статических массивов, размер которых фиксирован на этапе компиляции, динамические массивы позволяют изменять размер во время выполнения программы. В C++ для этого используется оператор new[] и delete[].

#include <iostream>

int main() {
    int size = 5;
    int* arr = new int[size]; // выделение памяти
    
    // Инициализация
    for(int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
    
    // Вывод
    for(int i = 0; i < size; i++) {
        std::cout << arr[i] << " ";
    }
    
    delete[] arr; // освобождение памяти
    return 0;
}

Важно помнить, что при работе с динамической памятью вы несете ответственность за её освобождение. Утечки памяти — одна из самых распространенных проблем в C++. Рекомендуется использовать умные указатели (std::unique_ptr, std::shared_ptr) из стандартной библиотеки для автоматического управления памятью.

2. Стек и очередь: классические структуры данных

Стек и очередь — две фундаментальные структуры данных, которые реализуют принципы LIFO (Last In, First Out) и FIFO (First In, First Out) соответственно. Рассмотрим их реализацию на C++ с использованием динамического массива.

Реализация стека

#include <iostream>
#include <stdexcept>

class Stack {
private:
    int* data;
    int capacity;
    int top;
    
public:
    Stack(int size) : capacity(size), top(-1) {
        data = new int[capacity];
    }
    
    ~Stack() {
        delete[] data;
    }
    
    void push(int value) {
        if(top >= capacity - 1) {
            throw std::overflow_error("Stack overflow");
        }
        data[++top] = value;
    }
    
    int pop() {
        if(isEmpty()) {
            throw std::underflow_error("Stack underflow");
        }
        return data[top--];
    }
    
    bool isEmpty() const {
        return top == -1;
    }
    
    int peek() const {
        if(isEmpty()) {
            throw std::underflow_error("Stack is empty");
        }
        return data[top];
    }
};

int main() {
    Stack stack(5);
    stack.push(10);
    stack.push(20);
    stack.push(30);
    
    std::cout << "Верхний элемент: " << stack.peek() << std::endl;
    std::cout << "Извлекаем: " << stack.pop() << std::endl;
    std::cout << "Извлекаем: " << stack.pop() << std::endl;
    
    return 0;
}

Реализация очереди

#include <iostream>

class Queue {
private:
    int* data;
    int capacity;
    int front;
    int rear;
    int count;
    
public:
    Queue(int size) : capacity(size), front(0), rear(-1), count(0) {
        data = new int[capacity];
    }
    
    ~Queue() {
        delete[] data;
    }
    
    void enqueue(int value) {
        if(isFull()) {
            throw std::overflow_error("Queue overflow");
        }
        rear = (rear + 1) % capacity;
        data[rear] = value;
        count++;
    }
    
    int dequeue() {
        if(isEmpty()) {
            throw std::underflow_error("Queue underflow");
        }
        int value = data[front];
        front = (front + 1) % capacity;
        count--;
        return value;
    }
    
    bool isEmpty() const {
        return count == 0;
    }
    
    bool isFull() const {
        return count == capacity;
    }
};

int main() {
    Queue queue(5);
    queue.enqueue(1);
    queue.enqueue(2);
    queue.enqueue(3);
    
    std::cout << "Извлекаем: " << queue.dequeue() << std::endl;
    std::cout << "Извлекаем: " << queue.dequeue() << std::endl;
    
    return 0;
}

Обратите внимание на использование кольцевого буфера в реализации очереди — это позволяет эффективно использовать память и избежать необходимости сдвигать элементы при извлечении.

3. Алгоритмы сортировки: от простого к эффективному

Сортировка — одна из самых изученных областей алгоритмов. Рассмотрим три ключевых алгоритма: пузырьковую сортировку (простая, но медленная), быструю сортировку (эффективная) и сортировку слиянием (стабильная).

Пузырьковая сортировка

void bubbleSort(int arr[], int n) {
    for(int i = 0; i < n - 1; i++) {
        bool swapped = false;
        for(int j = 0; j < n - i - 1; j++) {
            if(arr[j] > arr[j + 1]) {
                std::swap(arr[j], arr[j + 1]);
                swapped = true;
            }
        }
        // Оптимизация: если не было обменов, массив уже отсортирован
        if(!swapped) break;
    }
}

Быстрая сортировка

int partition(int arr[], int low, int high) {
    int pivot = arr[high];
    int i = low - 1;
    
    for(int j = low; j < high; j++) {
        if(arr[j] <= pivot) {
            i++;
            std::swap(arr[i], arr[j]);
        }
    }
    std::swap(arr[i + 1], arr[high]);
    return i + 1;
}

void quickSort(int arr[], int low, int high) {
    if(low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

Сортировка слиянием

void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    
    int* L = new int[n                

Блоги

Рекомендаций по книгам