Add 4.3 paragraph files
This commit is contained in:
parent
486a05ba3f
commit
869f22acce
2 changed files with 334 additions and 0 deletions
269
exercices/ai_exercises/ai_exercises.c
Normal file
269
exercices/ai_exercises/ai_exercises.c
Normal 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;
|
||||||
|
}
|
||||||
65
exercices/functions/par_4_3.c
Normal file
65
exercices/functions/par_4_3.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue