From 6ddc69fec49eec4e80a78350550632d5309c35cb Mon Sep 17 00:00:00 2001 From: Charlie Root Date: Tue, 7 Apr 2026 10:42:13 +0300 Subject: [PATCH] sliding_win --- lib/swm_min.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/swm_min.h | 41 +++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 lib/swm_min.c create mode 100644 lib/swm_min.h diff --git a/lib/swm_min.c b/lib/swm_min.c new file mode 100644 index 0000000..b6494a4 --- /dev/null +++ b/lib/swm_min.c @@ -0,0 +1,99 @@ +/* sliding_window_min.c */ +#include "sliding_window_min.h" +#include +#include + +struct SlidingWindowMin { + int* data; /* кольцевой буфер значений */ + int* deq; /* deque индексов (тоже кольцевой) */ + int dq_head; + int dq_tail; + int deq_count; + int cur_pos; + int window_size; +}; + +SlidingWindowMin* swm_create(int window_size) +{ + if (window_size <= 0) { + return NULL; + } + + SlidingWindowMin* swm = (SlidingWindowMin*)malloc(sizeof(SlidingWindowMin)); + if (!swm) { + return NULL; + } + + swm->data = (int*)malloc((size_t)window_size * sizeof(int)); + if (!swm->data) { + free(swm); + return NULL; + } + + swm->deq = (int*)malloc((size_t)window_size * sizeof(int)); + if (!swm->deq) { + free(swm->data); + free(swm); + return NULL; + } + + swm->window_size = window_size; + swm->dq_head = 0; + swm->dq_tail = 0; + swm->deq_count = 0; + swm->cur_pos = 0; + + return swm; +} + +void swm_destroy(SlidingWindowMin* swm) +{ + if (swm) { + free(swm->data); + free(swm->deq); + free(swm); + } +} + +void swm_add(SlidingWindowMin* swm, int val) +{ + if (!swm) return; + + int idx = swm->cur_pos; + int w = swm->window_size; + + /* записываем в кольцевой буфер */ + swm->data[idx % w] = val; + + /* 1. удаляем из начала deque индексы, которые уже вышли за окно */ + while (swm->deq_count > 0 && swm->deq[swm->dq_head] <= idx - w) { + swm->dq_head = (swm->dq_head + 1) % w; + swm->deq_count--; + } + + /* 2. удаляем из хвоста все элементы, которые хуже текущего */ + while (swm->deq_count > 0) { + int last_idx = swm->deq[(swm->dq_tail - 1 + w) % w]; + if (swm->data[last_idx % w] < val) { + break; + } + swm->dq_tail = (swm->dq_tail - 1 + w) % w; + swm->deq_count--; + } + + /* 3. добавляем текущий индекс */ + swm->deq[swm->dq_tail] = idx; + swm->dq_tail = (swm->dq_tail + 1) % w; + swm->deq_count++; + + swm->cur_pos++; +} + +int swm_get_min(const SlidingWindowMin* swm) +{ + if (!swm || swm->deq_count == 0) { + return INT_MAX; + } + int min_idx = swm->deq[swm->dq_head]; + return swm->data[min_idx % swm->window_size]; +} diff --git a/lib/swm_min.h b/lib/swm_min.h new file mode 100644 index 0000000..d923734 --- /dev/null +++ b/lib/swm_min.h @@ -0,0 +1,41 @@ +/* sliding_window_min.h */ +#ifndef SLIDING_WINDOW_MIN_H +#define SLIDING_WINDOW_MIN_H + +#include /* для size_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct SlidingWindowMin SlidingWindowMin; + +/** + * Создаёт новую структуру скользящего минимума. + * @param window_size размер окна (должен быть > 0) + * @return указатель на структуру или NULL при ошибке выделения памяти + */ +SlidingWindowMin* swm_create(int window_size); + +/** + * Уничтожает структуру и освобождает всю динамически выделенную память. + */ +void swm_destroy(SlidingWindowMin* swm); + +/** + * Добавляет новое значение в окно. + * После вызова swm_get_min() сразу вернёт минимум последних min(window_size, добавленных) значений. + */ +void swm_add(SlidingWindowMin* swm, int val); + +/** + * Возвращает текущий минимум в окне. + * Если окно пустое — возвращает INT_MAX. + */ +int swm_get_min(const SlidingWindowMin* swm); + +#ifdef __cplusplus +} +#endif + +#endif /* SLIDING_WINDOW_MIN_H */