Update cv7/program.c

This commit is contained in:
Yurii Chechur 2024-11-13 14:18:36 +00:00
parent 6f911eac8c
commit 9748e39462

View File

@ -6,113 +6,144 @@
// Структура вузла дерева // Структура вузла дерева
struct TreeNode { struct TreeNode {
char *value; // текст питання або відповіді char value[SIZE]; // текст питання або відповіді
struct TreeNode *left; // "так" гілка struct TreeNode *left; // "так" гілка
struct TreeNode *right; // "ні" гілка struct TreeNode *right; // "ні" гілка
}; };
// Функція для створення вузла дерева з текстом
struct TreeNode* createNode(const char *text) { struct TreeNode *read_tree(FILE *file) {
struct TreeNode *node = (struct TreeNode*) malloc(sizeof(struct TreeNode)); char buffer[SIZE];
node->value = strdup(text);
// Зчитуємо рядок тексту для поточного вузла
if (fgets(buffer, SIZE, file) == NULL) {
return NULL; // Кінець файлу або помилка читання
}
// Виділяємо пам'ять для нового вузла
struct TreeNode *node = (struct TreeNode *)malloc(sizeof(struct TreeNode));
if (node == NULL) {
perror("Не вдалося виділити пам'ять");
exit(EXIT_FAILURE);
}
// Копіюємо значення в новий вузол
strncpy(node->value, buffer, SIZE);
node->value[strcspn(node->value, "\n")] = '\0'; // Видаляємо символ нового рядка
node->left = NULL; node->left = NULL;
node->right = NULL; node->right = NULL;
// Перевіряємо, чи є вузол питанням (якщо починається з '#')
if (node->value[0] == '#') {
// Якщо це питання, рекурсивно зчитуємо ліве і праве піддерева
node->left = read_tree(file); // Піддерево для відповіді "так"
node->right = read_tree(file); // Піддерево для відповіді "ні"
}
// Повертаємо створений вузол (або лист, або вузол з піддеревами)
return node; return node;
} }
// Функція для завантаження бази знань у форматі pre-order
struct TreeNode* loadTree(FILE *file) {
char buffer[SIZE];
if (!fgets(buffer, SIZE, file) || buffer[0] == '\n') {
return NULL;
}
// Створюємо вузол для поточного рядка void read_code(char *code, int size, FILE *file) {
struct TreeNode *node = createNode(buffer); // Очищаємо буфер перед використанням
memset(code, 0, size);
// Якщо це відповідь (починається з '*'), то повертаємо листовий вузол // Зчитуємо код з файлу або stdin
if (buffer[0] == '*') { if (fgets(code, size, file) == NULL) {
return node; printf("Помилка: не вдалося зчитати код\n");
}
// Інакше рекурсивно завантажуємо лівий і правий нащадки
node->left = loadTree(file);
node->right = loadTree(file);
return node;
}
// Рекурсивна функція для підрахунку товарів у базі знань
int countItems(struct TreeNode *node) {
if (node == NULL) {
return 0;
}
if (node->left == NULL && node->right == NULL) {
return 1; // Листовий вузол є товаром
}
return countItems(node->left) + countItems(node->right);
}
// Функція для запуску експертної системи з питаннями і відповідями
void runExpertSystem(struct TreeNode *node) {
if (node == NULL) return;
// Виводимо поточне питання або відповідь
printf("%s", node->value);
// Якщо це листовий вузол, то закінчуємо роботу
if (node->left == NULL && node->right == NULL) {
printf("Koniec\n");
return; return;
} }
// Отримуємо відповідь користувача // Видаляємо символ нового рядка, якщо він є
char answer; code[strcspn(code, "\n")] = '\0';
scanf(" %c", &answer); // пробіл перед %c для пропуску зайвих пробілів }
// Переходимо до відповідного нащадка
if (answer == 'a') { void traverse_tree(struct TreeNode *root, const char *code) {
runExpertSystem(node->left); struct TreeNode *current = root; // Починаємо з кореня дерева
} else if (answer == 'n') {
runExpertSystem(node->right); for (int i = 0; i < strlen(code); i++) {
// Перевірка на символ "0" або "1"
if (code[i] == '0') {
current = current->left; // Переходимо вліво
} else if (code[i] == '1') {
current = current->right; // Переходимо вправо
} else { } else {
printf("Nerozumiem\n"); // Неправильна відповідь printf("Помилка: код містить некоректний символ '%c'\n", code[i]);
return;
}
// Перевіряємо, чи не вийшли за межі дерева
if (current == NULL) {
printf("Помилка: шлях у коді виходить за межі дерева\n");
return;
}
}
// Виводимо результат, якщо досягли листа
if (current->left == NULL && current->right == NULL) {
printf("Відповідь: %s\n", current->value);
} else {
printf("Помилка: код не веде до кінцевої відповіді\n");
} }
} }
// Функція для очищення пам'яті
void freeTree(struct TreeNode *node) {
if (node == NULL) return; void destroy_tree(struct TreeNode *node) {
freeTree(node->left); if (node == NULL) {
freeTree(node->right); return; // Якщо вузол порожній, просто повертаємося
free(node->value); }
// Рекурсивно очищаємо ліве і праве піддерева
destroy_tree(node->left);
destroy_tree(node->right);
// Звільняємо пам'ять для поточного вузла
free(node); free(node);
} }
int main() { int validate_code(const char *code) {
// Відкриваємо файл з базою знань // Перевірка на довжину рядка
// В даному випадку, ми використовуємо stdin (вхід з консолі) if (strlen(code) >= SIZE) {
struct TreeNode *root = loadTree(stdin); printf("Помилка: код перевищує допустиму довжину\n");
// Перевірка наявності порожнього рядка після бази знань
if (root == NULL) {
printf("Помилка: База знань некоректна або пуста.\n");
return 0; return 0;
} }
// Рахуємо кількість товарів і виводимо повідомлення // Перевірка кожного символу
int itemCount = countItems(root); for (int i = 0; i < strlen(code); i++) {
printf("Expert z bufetu to vie.\n"); if (code[i] != '0' && code[i] != '1') {
printf("Pozna %d druhov ovocia a zeleniny.\n", itemCount); printf("Помилка: код містить некоректний символ '%c'\n", code[i]);
printf("Odpovedajte 'a' pre prvu moznost alebo 'n' pre druhu moznost.\n"); return 0;
}
}
// Запуск експертної системи return 1; // Код коректний
runExpertSystem(root); }
// Виведення повідомлення про завершення вводу
printf("Koniec vstupu\n");
// Звільняємо пам'ять int main() {
freeTree(root); // Зчитуємо дерево
struct TreeNode *root = read_tree(stdin);
// Зчитуємо код для навігації
char code[SIZE];
printf("Введіть код для навігації деревом: ");
read_code(code, SIZE, stdin);
// Перевірка коректності коду
if (!validate_code(code)) {
destroy_tree(root); // Очищення дерева перед завершенням програми
return 1; // Завершення програми через некоректний код
}
// Навігація деревом за допомогою коду та виведення результату
traverse_tree(root, code);
printf("\n");
// Очищення пам'яті, зайнятої деревом
destroy_tree(root);
return 0; return 0;
} }