c_programming_language/exercices/ai_exercises/ai_exercises.c
2026-02-08 20:16:38 +03:00

269 lines
8.9 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* УПРАЖНЕНИЯ ПО РАБОТЕ СО СТЕКОМ В C
* ===================================
*
* Теория:
* -------
* Стек - структура данных LIFO (Last In, First Out)
* Операции: push (добавить), pop (удалить), peek (посмотреть), isEmpty
*
* В C есть два типа памяти:
* - СТЕК (Stack) - автоматическая, быстрая, ограниченная, локальные переменные
* - КУЧА (Heap) - динамическая (malloc/free), медленная, большая
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}