Add 4.3 paragraph files

This commit is contained in:
t0xa 2026-02-08 20:16:38 +03:00
parent 486a05ba3f
commit 869f22acce
2 changed files with 334 additions and 0 deletions

View file

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

View file

@ -0,0 +1,65 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}
}
}