/* * УПРАЖНЕНИЯ ПО РАБОТЕ СО СТЕКОМ В 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; }