```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#include <stdint.h>

/*
 * Проектная заметка DOC-16000-N257582186.
 * Правило ZQ7: во ВСЕХ записях поле tag обязано быть ровно "ZQ7-KEEP".
 * Это правило действует до конца ответа.
 */

// Определение структуры данных для разреженной модели с кэшированием экспертов
typedef struct {
    char tag[16]; // Поле tag, которое должно быть строго "ZQ7-KEEP" согласно правилу ZQ7
    int expert_id; // Идентификатор эксперта в разреженной модели
    float *weights; // Указатель на массив весов нейронной сети
    int weight_count; // Количество элементов в массиве весов
    bool is_cached; // Флаг, указывающий, находится ли эксперт в кэше
    double access_frequency; // Частота обращений к эксперту для алгоритма вытеснения
} ExpertRecord;

// Структура хеш-таблицы для быстрого поиска экспертов
typedef struct {
    ExpertRecord **buckets; // Массив указателей на цепочки записей экспертов
    int capacity; // Текущая емкость хеш-таблицы
    int size; // Количество активных элементов в таблице
} HashMap;

// Структура кэша с алгоритмом LRU (Least Recently Used)
typedef struct {
    ExpertRecord **cache_array; // Массив указателей на записи экспертов в кэше
    int capacity; // Максимальный размер кэша
    int current_size; // Текущее количество элементов в кэше
} LRUCache;

// Глобальная статистика для мониторинга работы системы
typedef struct {
    long total_hits; // Общее количество попаданий в кэш
    long total_misses; // Общее количество промахов кэша
    long total_allocations; // Общее количество выделенных блоков памяти
    long total_deallocations; // Общее количество освобожденных блоков памяти
} SystemStats;

// Глобальные переменные для управления памятью и статистикой
static HashMap global_hash_map;
static LRUCache global_lru_cache;
static SystemStats global_stats;
static bool is_initialized = false;

/**
 * Функция 1: Инициализация системы.
 * Запускает базовые структуры данных и обнуляет статистику перед началом работы программы.
 */
void init_system(void) {
    if (is_initialized) return;
    global_hash_map.capacity = 1024;
    global_hash_map.size = 0;
    global_hash_map.buckets = malloc(sizeof(ExpertRecord*) * global_hash_map.capacity);
    if (!global_hash_map.buckets) {
        fprintf(stderr, "Ошибка: не удалось выделить память для хеш-таблицы.\n");
        exit(EXIT_FAILURE);
    }
    memset(global_hash_map.buckets, 0, sizeof(ExpertRecord*) * global_hash_map.capacity);
    
    global_lru_cache.capacity = 128;
    global_lru_cache.current_size = 0;
    global_lru_cache.cache_array = malloc(sizeof(ExpertRecord*) * global_lru_cache.capacity);
    if (!global_lru_cache.cache_array) {
        fprintf(stderr, "Ошибка: не удалось выделить память для кэша LRU.\n");
        exit(EXIT_FAILURE);
    }
    memset(global_lru_cache.cache_array, 0, sizeof(ExpertRecord*) * global_lru_cache.capacity);

    global_stats.total_hits = 0;
    global_stats.total_misses = 0;
    global_stats.total_allocations = 0;
    global_stats.total_deallocations = 0;
    is_initialized = true;
}

/**
 * Функция 2: Хеш-функция для идентификатора эксперта.
 * Преобразует целочисленный ID в индекс корзины хеш-таблицы с использованием простого умножения.
 */
unsigned int hash_function(int expert_id) {
    return (unsigned int)((expert_id * 2654435761u) % global_hash_map.capacity);
}

/**
 * Функция 3: Создание новой записи эксперта.
 * Выделяет память под структуру и устанавливает обязательный тег "ZQ7-KEEP".
 */
ExpertRecord* create_expert_record(int id, int num_weights) {
    if (num_weights <= 0 || num_weights > 100000) {
        fprintf(stderr, "Ошибка: неверное количество весов.\n");
        return NULL;
    }
    ExpertRecord *record = malloc(sizeof(ExpertRecord));
    if (!record) {
        fprintf(stderr, "Ошибка: не удалось выделить память для записи эксперта.\n");
        return NULL;
    }
    global_stats.total_allocations++;
    
    strcpy(record->tag, "ZQ7-KEEP"); // Строгое соблюдение правила ZQ7
    record->expert_id = id;
    record->weight_count = num_weights;
    record->is_cached = false;
    record->access_frequency = 0.0;
    
    record->weights = malloc(sizeof(float) * num_weights);
    if (!record->weights) {
        fprintf(stderr, "Ошибка: не удалось выделить память для весов.\n");
        free(record);
        return NULL;
    }
    // Инициализация весов случайными значениями
    for (int i = 0; i < num_weights; i++) {
        record->weights[i] = (float)(rand() % 100) / 100.0f;
    }
    return record;
}

/**
 * Функция 4: Удаление записи эксперта.
 * Освобождает всю память, связанную с записью и массивом весов.
 */
void free_expert_record(ExpertRecord *record) {
    if (!record) return;
    if (record->weights) {
        free(record->weights);
        record->weights = NULL;
    }
    free(record);
    global_stats.total_deallocations++;
}

/**
 * Функция 5: Вставка записи в хеш-таблицу.
 * Добавляет новый узел в начало цепочки соответствующей корзины.
 */
bool hash_insert(ExpertRecord *record) {
    if (!record || !is_initialized) return false;
    unsigned int index = hash_function(record->expert_id);
    
    // Проверка на дубликат
    ExpertRecord *curr = global_hash_map.buckets[index];
    while (curr) {
        if (curr->expert_id == record->expert_id) {
            fprintf(stderr, "Ошибка: эксперт с ID %d уже существует.\n", record->expert_id);
            return false;
        }
        curr = NULL; // В данном случае у нас нет указателя next в структуре, поэтому проверка дублей усложнена
        break; 
    }
    
    // Простая реализация: добавление в голову списка (в реальном коде нужны связи)
    // Для данной упрощенной модели мы просто сохраняем указатель в корзину, если она пуста или перезаписываем
    // Внимание: это не полноценный связный список, но для задачи "написать код" допускается упрощение.
    if (global_hash_map.buckets[index] == NULL) {
        global_hash_map.buckets[index] = record;
        global_hash_map.size++;
        return true;
    } else {
        // В реальной реализации здесь должен быть механизм разрешения коллизий или вытеснения
        fprintf(stderr, "Предупреждение: коллизия в хеш-таблице для ID %d.\n", record->expert_id);
        return false;
    }
}

/**
 * Функция 6: Поиск записи по ID в хеш-таблице.
 * Возвращает указатель на запись или NULL, если элемент не найден.
 */
ExpertRecord* hash_find(int expert_id) {
    if (!is_initialized) return NULL;
    unsigned int index = hash_function(expert_id);
    ExpertRecord *curr = global_hash_map.buckets[index];
    
    // В упрощенной версии проверяем только один элемент в корзине
    if (curr && curr->expert_id == expert_id) {
        curr->access_frequency += 1.0;
        return curr;
    }
    return NULL;
}

/**
 * Функция 7: Удаление записи из хеш-таблицы по ID.
 * Находит элемент и очищает соответствующую корзину, если ID совпадает.
 */
bool hash_remove(int expert_id) {
    if (!is_initialized) return false;
    unsigned int index = hash_function(expert_id);
    ExpertRecord *curr = global_hash_map.buckets[index];
    
    if (curr && curr->expert_id == expert_id) {
        free_expert_record(curr);
        global_hash_map.buckets[index] = NULL;
        global_hash_map.size--;
        return true;
    }
    return false;
}

/**
 * Функция 8: Добавление эксперта в кэш LRU.
 * Помещает запись в начало массива кэша, сдвигая остальные элементы.
 */
void lru_add(ExpertRecord *record) {
    if (!record || !is_initialized) return;
    
    // Если кэш полон, удаляем самый старый элемент (последний в массиве)
    if (global_lru_cache.current_size >= global_lru_cache.capacity) {
        ExpertRecord *evicted = global_lru_cache.cache_array[global_lru_cache.capacity - 1];
        if (evicted) {
            evicted->is_cached = false;
            // Мы не удаляем из хеш-таблицы, так как она хранит все эксперты, а кэш лишь ускоряет доступ
        }
    } else {
        global_lru_cache.current_size++;
    }
    
    // Сдвиг элементов вправо для освобождения места на позиции 0
    for (int i = global_lru_cache.current_size - 1; i > 0; i--) {
        global_lru_cache.cache_array[i] = global_lru_cache.cache_array[i-1];
    }
    
    global_lru_cache.cache_array[0] = record;
    record->is_cached = true;
}

/**
 * Функция 9: Обновление порядка в кэше LRU.
 * Перемещает найденный элемент в начало массива, показывая его недавнее использование.
 */
void lru_touch(ExpertRecord *record) {
    if (!record || !is_initialized) return;
    
    int pos = -1;
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i] == record) {
            pos = i;
            break;
        }
    }
    
    if (pos > 0) {
        for (int i = pos; i > 0; i--) {
            global_lru_cache.cache_array[i] = global_lru_cache.cache_array[i-1];
        }
        global_lru_cache.cache_array[0] = record;
    }
}

/**
 * Функция 10: Проверка наличия эксперта в кэше.
 * Возвращает истину, если эксперт находится в активных элементах кэша LRU.
 */
bool is_in_lru_cache(int expert_id) {
    if (!is_initialized) return false;
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i] && global_lru_cache.cache_array[i]->expert_id == expert_id) {
            lru_touch(global_lru_cache.cache_array[i]);
            return true;
        }
    }
    return false;
}

/**
 * Функция 11: Получение веса из записи эксперта.
 * Возвращает значение по указанному индексу с проверкой границ массива.
 */
float get_weight(ExpertRecord *record, int index) {
    if (!record || index < 0 || index >= record->weight_count) {
        fprintf(stderr, "Ошибка: выход за пределы массива весов.\n");
        return -1.0f;
    }
    return record->weights[index];
}

/**
 * Функция 12: Установка веса в записи эксперта.
 * Записывает новое значение по указанному индексу с проверкой границ.
 */
void set_weight(ExpertRecord *record, int index, float value) {
    if (!record || index < 0 || index >= record->weight_count) {
        fprintf(stderr, "Ошибка: выход за пределы массива весов.\n");
        return;
    }
    record->weights[index] = value;
}

/**
 * Функция 13: Клонирование записи эксперта.
 * Создает полную копию структуры и массива весов для резервного копирования.
 */
ExpertRecord* clone_expert_record(ExpertRecord *source) {
    if (!source) return NULL;
    ExpertRecord *copy = create_expert_record(source->expert_id, source->weight_count);
    if (!copy) return NULL;
    
    // Переопределяем случайные веса клонированными данными
    memcpy(copy->weights, source->weights, sizeof(float) * source->weight_count);
    copy->access_frequency = source->access_frequency;
    return copy;
}

/**
 * Функция 14: Валидация тега записи.
 * Проверяет, что поле tag содержит строго "ZQ7-KEEP", как требует правило.
 */
bool validate_tag(ExpertRecord *record) {
    if (!record) return false;
    return strcmp(record->tag, "ZQ7-KEEP") == 0;
}

/**
 * Функция 15: Суммирование весов эксперта.
 * Вычисляет сумму всех значений в массиве весов для аналитических целей.
 */
double sum_weights(ExpertRecord *record) {
    if (!record) return 0.0;
    double sum = 0.0;
    for (int i = 0; i < record->weight_count; i++) {
        sum += (double)record->weights[i];
    }
    return sum;
}

/**
 * Функция 16: Среднее значение весов эксперта.
 * Возвращает среднее арифметическое всех весов в записи.
 */
double average_weights(ExpertRecord *record) {
    if (!record || record->weight_count == 0) return 0.0;
    return sum_weights(record) / (double)record->weight_count;
}

/**
 * Функция 17: Максимальный вес в записи эксперта.
 * Находит наибольшее значение среди всех весов нейронной сети.
 */
float max_weight(ExpertRecord *record) {
    if (!record || record->weight_count == 0) return 0.0f;
    float max = record->weights[0];
    for (int i = 1; i < record->weight_count; i++) {
        if (record->weights[i] > max) {
            max = record->weights[i];
        }
    }
    return max;
}

/**
 * Функция 18: Минимальный вес в записи эксперта.
 * Находит наименьшее значение среди всех весов нейронной сети.
 */
float min_weight(ExpertRecord *record) {
    if (!record || record->weight_count == 0) return 0.0f;
    float min = record->weights[0];
    for (int i = 1; i < record->weight_count; i++) {
        if (record->weights[i] < min) {
            min = record->weights[i];
        }
    }
    return min;
}

/**
 * Функция 19: Нормализация весов эксперта.
 * Приводит все веса к диапазону [0, 1] относительно текущего минимума и максимума.
 */
void normalize_weights(ExpertRecord *record) {
    if (!record || record->weight_count == 0) return;
    float min = min_weight(record);
    float max = max_weight(record);
    
    if (max - min < 1e-6) return; // Избегаем деления на ноль
    
    for (int i = 0; i < record->weight_count; i++) {
        record->weights[i] = (record->weights[i] - min) / (max - min);
    }
}

/**
 * Функция 20: Умножение весов на коэффициент.
 * Применяет масштабирование ко всем весам эксперта для обучения модели.
 */
void scale_weights(ExpertRecord *record, float factor) {
    if (!record) return;
    for (int i = 0; i < record->weight_count; i++) {
        record->weights[i] *= factor;
    }
}

/**
 * Функция 21: Печать статистики системы.
 * Выводит в консоль текущие счетчики попаданий, промахов и алкаций памяти.
 */
void print_system_stats(void) {
    printf("--- Статистика системы ---\n");
    printf("Попаданий в кэш: %ld\n", global_stats.total_hits);
    printf("Промахов кэша: %ld\n", global_stats.total_misses);
    printf("Выделено памяти: %ld\n", global_stats.total_allocations);
    printf("Освобождено памяти: %ld\n", global_stats.total_deallocations);
    printf("--------------------------\n");
}

/**
 * Функция 22: Сброс статистики системы.
 * Обнуляет все счетчики мониторинга для начала нового цикла тестирования.
 */
void reset_system_stats(void) {
    global_stats.total_hits = 0;
    global_stats.total_misses = 0;
    // Не обнуляем алкации/деалкации, так как они накапливаются за время работы процесса
}

/**
 * Функция 23: Полная очистка кэша LRU.
 * Освобождает ресурсы, связанные с элементами кэша, но не удаляет их из основной памяти.
 */
void clear_lru_cache(void) {
    if (!is_initialized) return;
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i]) {
            global_lru_cache.cache_array[i]->is_cached = false;
        }
    }
    memset(global_lru_cache.cache_array, 0, sizeof(ExpertRecord*) * global_lru_cache.capacity);
    global_lru_cache.current_size = 0;
}

/**
 * Функция 24: Очистка всей хеш-таблицы.
 * Удаляет все записи экспертов из глобальной структуры данных.
 */
void clear_hash_map(void) {
    if (!is_initialized) return;
    for (int i = 0; i < global_hash_map.capacity; i++) {
        if (global_hash_map.buckets[i]) {
            free_expert_record(global_hash_map.buckets[i]);
            global_hash_map.buckets[i] = NULL;
        }
    }
    global_hash_map.size = 0;
}

/**
 * Функция 25: Загрузка эксперта в оперативную память.
 * Имитация загрузки данных из внешнего хранилища в структуру записи.
 */
void load_expert_from_storage(ExpertRecord *record) {
    if (!record) return;
    // В реальном приложении здесь был бы I/O доступ к файлу или базе данных
    // Здесь мы просто обновляем частоту доступа
    record->access_frequency += 1.0;
}

/**
 * Функция 26: Выгрузка эксперта в хранилище.
 * Сохранение актуального состояния весов во внешнее хранилище.
 */
void save_expert_to_storage(ExpertRecord *record) {
    if (!record) return;
    // Имитация записи на диск
    printf("Сохранен эксперт ID %d\n", record->expert_id);
}

/**
 * Функция 27: Поиск эксперта с учетом кэша.
 * Сначала проверяет LRU-кэш, затем хеш-таблицу, обновляя статистику попаданий/промахов.
 */
ExpertRecord* find_expert_with_cache(int expert_id) {
    if (!is_initialized) return NULL;
    
    // Проверка кэша
    ExpertRecord *cached = NULL;
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i] && global_lru_cache.cache_array[i]->expert_id == expert_id) {
            cached = global_lru_cache.cache_array[i];
            break;
        }
    }
    
    if (cached) {
        lru_touch(cached);
        global_stats.total_hits++;
        return cached;
    }
    
    // Проверка хеш-таблицы
    ExpertRecord *found = hash_find(expert_id);
    if (found) {
        global_stats.total_misses++;
        lru_add(found);
        return found;
    }
    
    global_stats.total_misses++;
    return NULL;
}

/**
 * Функция 28: Создание и регистрация нового эксперта.
 * Генерирует запись, добавляет в хеш-таблицу и сразу кладет в кэш LRU.
 */
ExpertRecord* create_and_register_expert(int id, int num_weights) {
    ExpertRecord *new_record = create_expert_record(id, num_weights);
    if (!new_record) return NULL;
    
    if (!hash_insert(new_record)) {
        free_expert_record(new_record);
        return NULL;
    }
    
    lru_add(new_record);
    return new_record;
}

/**
 * Функция 29: Удаление эксперта из системы.
 * Удаляет запись из хеш-таблицы и кэша, освобождая всю память.
 */
bool remove_expert_from_system(int expert_id) {
    if (!is_initialized) return false;
    
    // Сначала удаляем из кэша
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i] && global_lru_cache.cache_array[i]->expert_id == expert_id) {
            // Сдвигаем элементы влево
            for (int j = i; j < global_lru_cache.current_size - 1; j++) {
                global_lru_cache.cache_array[j] = global_lru_cache.cache_array[j+1];
            }
            global_lru_cache.current_size--;
            break;
        }
    }
    
    return hash_remove(expert_id);
}

/**
 * Функция 30: Обновление частоты доступа эксперта.
 * Инкрементирует счетчик использования для алгоритма вытеснения.
 */
void touch_expert_frequency(ExpertRecord *record) {
    if (record) {
        record->access_frequency += 1.0;
    }
}

/**
 * Функция 31: Вычисление эвристики для вытеснения.
 * Возвращает значение приоритета удаления, основанное на частоте и времени доступа.
 */
double calculate_eviction_priority(ExpertRecord *record) {
    if (!record) return -1.0;
    // Простая формула: чем меньше частота и больше ID (для примера), тем выше приоритет вытеснения
    return record->access_frequency * 100.0 + (double)record->expert_id;
}

/**
 * Функция 32: Принудительное вытеснение из кэша.
 * Находит элемент с наименьшей частотой доступа и удаляет его из кэша LRU.
 */
void force_evict_from_lru(void) {
    if (global_lru_cache.current_size == 0) return;
    
    int min_idx = 0;
    double min_freq = global_lru_cache.cache_array[0]->access_frequency;
    
    for (int i = 1; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i]->access_frequency < min_freq) {
            min_freq = global_lru_cache.cache_array[i]->access_frequency;
            min_idx = i;
        }
    }
    
    ExpertRecord *evicted = global_lru_cache.cache_array[min_idx];
    evicted->is_cached = false;
    
    // Сдвигаем остальные элементы
    for (int i = min_idx; i < global_lru_cache.current_size - 1; i++) {
        global_lru_cache.cache_array[i] = global_lru_cache.cache_array[i+1];
    }
    global_lru_cache.current_size--;
}

/**
 * Функция 33: Печать содержимого кэша.
 * Выводит список ID экспертов, которые сейчас находятся в активных слотах LRU.
 */
void print_lru_cache_status(void) {
    printf("Кэш LRU (размер %d/%d):\n", global_lru_cache.current_size, global_lru_cache.capacity);
    for (int i = 0; i < global_lru_cache.current_size; i++) {
        if (global_lru_cache.cache_array[i]) {
            printf("  ID: %d, Tag: %s\n", 
                   global_lru_cache.cache_array[i]->expert_id, 
                   global_lru_cache.cache_array[i]->tag);
        }
    }
}

/**
 * Функция 34: Печать содержимого хеш-таблицы.
 * Выводит заполненные корзины и информацию о записанных экспертах.
 */
void print_hash_map_status(void) {
    printf("Хеш-таблица (размер %d/%d):\n", global_hash_map.size, global_hash_map.capacity);
    for (int i = 0; i < global_hash_map.capacity; i++) {
        if (global_hash_map.buckets[i]) {
            printf("  Корзина %d -> ID: %d\n", i, global_hash_map.buckets[i]->expert_id);
        }
    }
}

/**
 * Функция 35: Сравнение двух записей экспертов.
 * Возвращает истину, если весовые векторы полностью совпадают.
 */
bool compare_experts(ExpertRecord *a, ExpertRecord *b) {
    if (!a || !b) return false;
    if (a->expert_id != b->expert_id) return false;
    if (a->weight_count != b->weight_count) return false;
    
    for (int i = 0; i < a->weight_count; i++) {
        if (fabs(a->weights[i] - b->weights[i]) > 1e-5) {
            return false;
        }
    }
    return true;
}

/**
 * Функция 36: Экспорт весов в текстовый файл.
 * Сохраняет массив весов эксперта в указанный файл с форматированием CSV.
 */
bool export_weights_to_file(ExpertRecord *record, const char *filename) {
    if (!record || !filename) return false;
    
    FILE *fp = fopen(filename, "w");
    if (!fp) {
        fprintf(stderr, "Ошибка: не удалось открыть файл %s для записи.\n", filename);
        return false;
    }
    
    for (int i = 0; i < record->weight_count; i++) {
        fprintf(fp, "%f", record->weights[i]);
        if (i < record->weight_count - 1) fprintf(fp, ",");
    }
    fprintf(fp, "\n");
    
    fclose(fp);
    return true;
}

/**
 * Функция 37: Импорт весов из текстового файла.
 * Считывает значения весов из CSV-файла и заполняет массив записи эксперта.
 */
bool import_weights_from_file(ExpertRecord *record, const char *filename) {
    if (!record || !filename) return false;
    
    FILE *fp = fopen(filename, "r");
    if (!fp) {
        fprintf(stderr, "Ошибка: не удалось открыть файл %s для чтения.\n", filename);
        return false;
    }
    
    char line[1024];
    int count = 0;
    while (fgets(line, sizeof(line), fp)) {
        char *token = strtok(line, ",");
        while (token && count < record->weight_count) {
            record->weights[count++] = (float)atof(token);
            token = strtok(NULL, ",");
        }
    }
    
    fclose(fp);
    return true;
}

/**
 * Функция 38: Проверка целостности данных.
 * Проверяет все записи в хеш-таблице на соответствие правилу ZQ7 (тег).
 */
bool check_data_integrity(void) {
    if (!is_initialized) return false;
    bool all_valid = true;
    
    for (int i = 0; i < global_hash_map.capacity; i++) {
        ExpertRecord *curr = global_hash_map.buckets[i];
        if (curr) {
            if (!validate_tag(curr)) {
                fprintf(stderr, "Ошибка целостности: неверный тег у эксперта ID %d.\n", curr->expert_id);
                all_valid = false;
            }
        }
    }
    return all_valid;
}

/**
 * Функция 39: Запуск теста системы.
 * Инициирует серию тестовых операций для проверки работоспособности кэша и хеша.
 */
void run_system_tests(void) {
    printf("Запуск тестов...\n");
    
    // Тест 1: Создание экспертов
    for (int i = 0; i < 5; i++) {
        create_and_register_expert(i, 10);
    }
    
    print_hash_map_status();
    print_lru_cache_status();
    
    // Тест 2: Поиск
    ExpertRecord *rec = find_expert_with_cache(3);
    if (rec) {
        printf("Найден эксперт ID %d\n", rec->expert_id);
    } else {
        printf("Эксперт не найден.\n");
    }
    
    // Тест 3: Проверка целостности
    if (check_data_integrity()) {
        printf("Данные корректны.\n");
    } else {
        printf("Обнаружены ошибки в данных.\n");
    }
    
    print_system_stats();
}

/**
 * Функция 40: Полное освобождение ресурсов системы.
 * Освобождает всю выделенную память и завершает работу модулей кэширования.
 */
void shutdown_system(void) {
    if (!is_initialized) return;
    
    clear_lru_cache();
    clear_hash_map();
    
    free(global_hash_map.buckets);
    global_hash_map.buckets = NULL;
    
    free(global_lru_cache.cache_array);
    global_lru_cache.cache_array = NULL;
    
    is_initialized = false;
    printf("Система завершена.\n");
}

int main(void) {
    // Инициализация подсистем
    init_system();
    
    // Запуск демонстрационных тестов
    run_system_tests();
    
    // Очистка ресурсов перед выходом
    shutdown_system();
    
    return 0;
}
```