diff --git a/exercices/ai_exercises/ai_exercises.c b/exercices/ai_exercises/ai_exercises.c new file mode 100644 index 0000000..4f31c84 --- /dev/null +++ b/exercices/ai_exercises/ai_exercises.c @@ -0,0 +1,269 @@ +/* + * УПРАЖНЕНИЯ ПО РАБОТЕ СО СТЕКОМ В C + * =================================== + * + * Теория: + * ------- + * Стек - структура данных LIFO (Last In, First Out) + * Операции: push (добавить), pop (удалить), peek (посмотреть), isEmpty + * + * В C есть два типа памяти: + * - СТЕК (Stack) - автоматическая, быстрая, ограниченная, локальные переменные + * - КУЧА (Heap) - динамическая (malloc/free), медленная, большая + */ + +#include +#include +#include +#include + +#define MAX_SIZE 100 + +/* ============================================================================ + * ЗАДАЧА 1: Базовый стек на массиве + * ============================================================================ + * Реализуй простой стек с операциями push, pop, peek, isEmpty + */ + +typedef struct { + int data[MAX_SIZE]; + int top; // индекс вершины стека +} Stack; + +// Инициализировать стек +void stack_init(Stack *s) { + // TODO: реализуй инициализацию +} + +// Проверить, пуст ли стек +bool stack_isEmpty(Stack *s) { + // TODO: реализуй проверку + return false; +} + +// Проверить, полон ли стек +bool stack_isFull(Stack *s) { + // TODO: реализуй проверку + return false; +} + +// Добавить элемент в стек +bool stack_push(Stack *s, int value) { + // TODO: реализуй push + // Проверь переполнение! + return false; +} + +// Удалить и вернуть элемент из стека +bool stack_pop(Stack *s, int *value) { + // TODO: реализуй pop + // Проверь, не пуст ли стек! + return false; +} + +// Посмотреть элемент на вершине без удаления +bool stack_peek(Stack *s, int *value) { + // TODO: реализуй peek + return false; +} + +void test_task1() { + printf("\n=== ЗАДАЧА 1: Базовый стек ===\n"); + Stack s; + stack_init(&s); + + // Тест push + stack_push(&s, 10); + stack_push(&s, 20); + stack_push(&s, 30); + + // Тест peek + int value; + if (stack_peek(&s, &value)) { + printf("Вершина стека: %d (ожидается 30)\n", value); + } + + // Тест pop + while (!stack_isEmpty(&s)) { + stack_pop(&s, &value); + printf("Pop: %d\n", value); + } +} + +/* ============================================================================ + * ЗАДАЧА 2: Перевернуть строку используя стек + * ============================================================================ + * Используй стек для переворачивания строки + */ + +void reverse_string(char *str) { + // TODO: используй стек для переворота строки + // Подсказка: помести каждый символ в стек, затем извлеки обратно +} + +void test_task2() { + printf("\n=== ЗАДАЧА 2: Перевернуть строку ===\n"); + char str[] = "Hello, Stack!"; + printf("До: %s\n", str); + reverse_string(str); + printf("После: %s\n", str); + printf("Ожидается: !kcatS ,olleH\n"); +} + +/* ============================================================================ + * ЗАДАЧА 3: Проверка сбалансированности скобок + * ============================================================================ + * Проверь, правильно ли расставлены скобки: (), [], {} + * Примеры: + * - "([])" -> true + * - "([)]" -> false + * - "{[()]}" -> true + */ + +bool is_balanced(const char *expr) { + // TODO: используй стек для проверки скобок + // Алгоритм: + // 1. При открывающей скобке - push + // 2. При закрывающей - pop и проверь соответствие + // 3. В конце стек должен быть пуст + return false; +} + +void test_task3() { + printf("\n=== ЗАДАЧА 3: Сбалансированность скобок ===\n"); + const char *tests[] = {"()", "([])", "([)]", "{[()]}", + "(((", "))", "{[(])}", ""}; + + for (int i = 0; i < 8; i++) { + printf("\"%s\" -> %s\n", tests[i], + is_balanced(tests[i]) ? "сбалансированы" : "НЕ сбалансированы"); + } +} + +/* ============================================================================ + * ЗАДАЧА 4: Калькулятор обратной польской нотации (RPN) + * ============================================================================ + * Вычисли выражение в постфиксной записи + * Пример: "3 4 + 2 *" = (3 + 4) * 2 = 14 + * + * Алгоритм: + * - Если число - push в стек + * - Если операция - pop два числа, выполни операцию, push результат + */ + +int evaluate_rpn(const char *expr) { + // TODO: реализуй RPN калькулятор + // Подсказка: используй strtok для разбора строки + return 0; +} + +void test_task4() { + printf("\n=== ЗАДАЧА 4: RPN Калькулятор ===\n"); + const char *expressions[] = { + "3 4 +", // 7 + "3 4 + 2 *", // 14 + "5 1 2 + 4 * + 3 -", // 14 + }; + + for (int i = 0; i < 3; i++) { + printf("\"%s\" = %d\n", expressions[i], evaluate_rpn(expressions[i])); + } +} + +/* ============================================================================ + * ЗАДАЧА 5: Стековая память vs Куча + * ============================================================================ + * Изучи разницу между стековой памятью и кучей + */ + +void demonstrate_stack_memory() { + printf("\n=== ЗАДАЧА 5: Стековая память ===\n"); + + // Локальные переменные - на стеке + int stack_var = 42; + int stack_array[10]; + + printf("Адрес stack_var: %p\n", (void *)&stack_var); + printf("Адрес stack_array: %p\n", (void *)stack_array); + + // Динамическая память - в куче + int *heap_var = malloc(sizeof(int)); + int *heap_array = malloc(10 * sizeof(int)); + + printf("Адрес heap_var: %p\n", (void *)heap_var); + printf("Адрес heap_array: %p\n", (void *)heap_array); + + printf("\nСтек растет вниз (адреса уменьшаются)\n"); + printf("Куча растет вверх (адреса увеличиваются)\n"); + + // TODO: попробуй создать рекурсивную функцию и посмотри + // как меняются адреса локальных переменных + + free(heap_var); + free(heap_array); +} + +/* ============================================================================ + * ЗАДАЧА 6: Динамический стек (бонус) + * ============================================================================ + * Реализуй стек, который растет при необходимости + */ + +typedef struct { + int *data; + int top; + int capacity; +} DynamicStack; + +void dynamic_stack_init(DynamicStack *s) { + // TODO: начальная емкость = 4 +} + +bool dynamic_stack_push(DynamicStack *s, int value) { + // TODO: если заполнен - удвой размер с помощью realloc + return false; +} + +bool dynamic_stack_pop(DynamicStack *s, int *value) { + // TODO: можешь также уменьшать размер при малой заполненности + return false; +} + +void dynamic_stack_free(DynamicStack *s) { + // TODO: освободи память +} + +void test_task6() { + printf("\n=== ЗАДАЧА 6: Динамический стек ===\n"); + DynamicStack s; + dynamic_stack_init(&s); + + // Добавь больше элементов, чем начальная емкость + for (int i = 0; i < 10; i++) { + dynamic_stack_push(&s, i); + printf("Pushed %d, capacity: %d\n", i, s.capacity); + } + + dynamic_stack_free(&s); +} + +/* ============================================================================ + * MAIN - Запуск всех тестов + * ============================================================================ + */ + +int main() { + printf("╔════════════════════════════════════════╗\n"); + printf("║ УПРАЖНЕНИЯ ПО СТЕКУ В C ║\n"); + printf("╚════════════════════════════════════════╝\n"); + + // Раскомментируй по мере выполнения задач + test_task1(); + // test_task2(); + // test_task3(); + // test_task4(); + // demonstrate_stack_memory(); + // test_task6(); + + return 0; +} diff --git a/exercices/functions/par_4_3.c b/exercices/functions/par_4_3.c new file mode 100644 index 0000000..517770f --- /dev/null +++ b/exercices/functions/par_4_3.c @@ -0,0 +1,65 @@ +#include +#include + +#define MAXOP 100 // Максимальный размер операдна (цифры) или оператора +#define NUMBER '0' // Признак числа + +int getop(char[]); +void push(double); +double pop(void); + +int main() { + int type; + double pop2; + char s[MAXOP]; + + while ((type = getop(s)) != EOF) { + switch (type) { + case NUMBER: + push(atof(s)); + break; + case '+': + push(pop() + pop()); + break; + case '*': + push(pop() * pop()); + break; + case '-': + /* + * Тут сначала извлекаем верхний операнд, из которого надо + * вычитать. В отличии от `+`, `*` для `-` и `/` порядок операндов + * важен. + * + * ---------- + * - + * 10 + * 20 + * ... + * ---------- + * + * Чтобы сделать вычитание - надо из 20 вычесть 10 - получается + * излекам со стека 10, затем 20 и делаем вычитание + */ + pop2 = pop(); + push(pop() - pop2); + break; + case '/': + /* + * Тут примерно то-же самое, только еще надо сделать проверку + * на ноль + */ + pop2 = pop(); + if (pop2 != 0.0) + push(pop() / pop2); + else + printf("Error: Division by zero\n"); + break; + case '\n': + printf("\t%.g\n", pop()); + break; + default: + printf("Error: Unknown operation %s\n", s); + break; + } + } +}