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