Advertisement
Week045

My Lab

May 18th, 2022
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.81 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. struct tree{                // Дерево в котором информационные поля - число или знак
  6.     char sign;
  7.     int num;
  8.     struct tree *left, *right;
  9. };
  10.  
  11. struct stack{               // Стек нужен для построения обратной польской записи
  12.     char c;
  13.     struct stack* next;
  14. };
  15.  
  16. char* polish(const char*, struct stack**);                  // Прототипы функций
  17. char pop(struct stack**);
  18. struct stack* push(struct stack**, char);
  19. int priority(char);
  20. struct tree* add(struct tree*, char, int);
  21. int calc(struct tree*);
  22. int isCorrect(char* string);
  23. int flag = 1;
  24.  
  25. char* polish(const char* str, struct stack** node){         // Функция, строящая обратную польскую запись
  26.     int i = 0, point = 0;
  27.     char* out;
  28.     if (!(out = (char*)malloc(50))) {
  29.         puts("Ошибка при работе с памятью!");
  30.         return 0;
  31.     }
  32.     printf("Исходное выражение %s\n", str);
  33.     while (*(str + i) != '\0' && *(str + i) != '='){        // Цикл пока не закончится строка или пока не встретим равно.
  34.         while (*(str + i) == ' ') i++;                      // Пропуск пробелов.
  35.         if (*(str + i) == ')'){                             // Если встречаем закрывающуюся скобку, то удаляем
  36.             while ((*node)->c != '(')
  37.                 *(out + point++) = pop(node);               // из стека все элементы до открывающейся скобки
  38.             pop(node);                                      // включительно и записываем в строку.
  39.         }
  40.         if (*(str + i) >= '0' && *(str + i) <= '9'){        // Если встречаем цифру, то записываем в строку все число
  41.             while (*(str + i) >= '0' && *(str + i) <= '9'){
  42.                 *(out + point++) = *(str + i);
  43.                 i++;
  44.             }
  45.             *(out + point++) = ' ';
  46.             i--;
  47.         }
  48.         if (*(str + i) == '(') {                            // Если встречаем открывающуюся скобку, то заносим в стек
  49.             *node = push(node, '(');                     // эту скобку
  50.         }
  51.         if (*(str + i) == '+' || *(str + i) == '-' || *(str + i) == '*' || *(str + i) == '/'){
  52.             while ((*node != NULL) && (priority((*node)->c) >= priority(*(str + i))))
  53.                 *(out + point++) = pop(node);               // Если встречаем оператор, то удаляем из стека все элементы
  54.             *node = push(node, *(str + i));              // с более низким приоритетом и записываем их в строку.
  55.         }                                                   // После этого записываем текущий знак в стек.
  56.         i++;
  57.     }
  58.     while (*node != NULL)                                   // Возможна такая ситуация, что в стеке остаются элементы,
  59.         *(out + point++) = pop(node);                       // поэтому их нужно записать в строку
  60.     *(out + point) = '\0';
  61.     printf("\nОбратная польская запись: %s\n", out);
  62.     return out;
  63. }
  64.  
  65. struct stack* push(struct stack** node, char c){            // Функция занесения узла в стек,
  66.     struct stack* s;
  67.     s = (struct stack*)malloc(sizeof(struct stack));
  68.     s -> c = c;
  69.     s -> next = *node;                                      // Установка указателя на следующий элемент на голову стека,
  70.     return s;                                               // тем самым, делая текущий узел головой стека
  71. }
  72.  
  73. char pop(struct stack** node){                              // Функция удаления узла из стека,
  74.     char c;                                                 // возвращает удаляемое значение
  75.     struct stack* ptr;
  76.     if (!*node) return '\0';                                // Если стек пустой возвращает \0
  77.     ptr = *node;
  78.     c = ptr -> c;                                           // смещение головы стека
  79.     if (ptr -> c == '(' || ptr -> c == '+' || ptr -> c == '-' || ptr -> c == '*' || ptr -> c == '/') {
  80.         *node = ptr -> next;
  81.     }
  82.     else *node = NULL;
  83.     free(ptr);                                              // Удаление узла
  84.     return c;
  85. }
  86.  
  87. int priority(char c){                                       // Возвращает приоритет операции.
  88.     switch (c){                                             // У умножения и деления наивысший приоритет - 3
  89.         case '*': case '/': return 3;                       // У сложения и вычитания - 2
  90.         case '+': case '-': return 2;                       // У закрывающейся скобки - 1
  91.         case ')': return 1;
  92.         default: return 0;
  93.     }
  94. }
  95.  
  96. struct tree* add(struct tree* node, char symbol, int number){               // Функция добавления узлов в дерево
  97.     if (!node){                                                             // Если дерево пустое - просто заносим все значения в корень
  98.         if (!(node = (struct tree*)malloc(sizeof(struct tree)))) {
  99.             puts("Ошибка при работе с памятью!");
  100.             return 0;
  101.         }
  102.         node -> num = number;
  103.         node -> sign = symbol;
  104.         node -> left = node -> right = NULL;
  105.         flag = 1;                                                           // Сброс флага для принудительного
  106.         return node;                                                        // занесения в левую ветвь
  107.     }
  108.     if (node -> sign == ' ') {                                              // Если записано число в узле, возвращаем этот узел
  109.         return node;
  110.     }
  111.     if (!node -> right){                                                    // Если в правой ветки нет,
  112.         node -> right = add(node -> right, symbol, number);           // создаем ее и заносим значения туда
  113.         return node;
  114.     }
  115.     if (node -> right){                                                     // Если правая ветка есть и там записан оператор,
  116.         if (node -> right -> sign != ' ') {                                 // то спускаемся к этому оператору
  117.             node -> right = add(node -> right, symbol, number);
  118.         } else {                                                            // Если записано число, то ставим флаг для принудительного
  119.             flag = 0;                                                       // перехода на левую ветку и спускаемся влево
  120.             node -> left = add(node -> left, symbol, number);
  121.         }
  122.     }
  123.     if (node -> right && flag == 0) {                                       // Принудительный спуск влево
  124.         node -> left = add(node -> left, symbol, number);
  125.     }
  126.     return node;
  127. }
  128.  
  129. int calc(struct tree* node){                                                // Функция, считающая выражения (обход дерева)
  130.     if (node){
  131.         if (node -> left) {
  132.             node -> num = calc(node -> left);                         // Спускаемся до конца влево
  133.         }
  134.         if (node -> right) {
  135.             switch (node -> sign) {                                         // Смотрим, что за знак в текущем узле
  136.                 case '+':                                                   // и в зависимости от знака делаем
  137.                     node -> num += calc(node -> right);               // операцию с числом из правой ветки
  138.                     break;
  139.                 case '-':
  140.                     node -> num -= calc(node -> right);
  141.                     break;
  142.                 case '*':
  143.                     node -> num *= calc(node -> right);
  144.                     break;
  145.                 case '/':
  146.                     node -> num /= calc(node -> right);
  147.                     break;
  148.             }
  149.         }
  150.     }
  151.     return node -> num;
  152. }
  153.  
  154. void showTree(struct tree* node, int depth){                                // Функция - вывод дерева
  155.     if (node) {                                                             // Пока node не пустой, идем вправо
  156.         showTree(node->right, depth + 1);
  157.     }
  158.     for (int i = 0; i < depth; i++) {                                       // Поскольку дерево лежит на боку,
  159.         printf("      ");                                                   // то depth сдвигает узел-потомок
  160.     }                                                                       // на несколько уровней вправо
  161.     if (node){
  162.         if (node -> sign == '+' || node -> sign == '*' || node -> sign == '-' || node -> sign == '/'){
  163.             printf("%c\n", node -> sign);
  164.         } else if (node -> num != 0){                                       // Если в узле знак - выводим знак
  165.             printf("%d\n", node -> num);                                    // Если в узле число - выводим число
  166.         }
  167.     } else {                                                                // Если узел пуст - выводим решетку
  168.         printf("#\n");
  169.     }
  170.     if (node){                                                              // Заходим до конца влево
  171.         showTree(node -> left, depth + 1);
  172.     }                                                                       // Поскольку дерево лежит на боку,
  173. }                                                                           // то логично, что первым будет самый правый элемент,
  174.                                                                             // а самым последним - самый левый
  175. int checkBrackets(char *string){
  176.     int bool = 0;                                                           // Проверка скобок
  177.     for (int i = 0; i < strlen(string); ++i) {                           // Если при проходе по строке
  178.         if (string[i] == '('){                                              // в какой-то момент bool станет < 0
  179.             bool++;                                                         // то функция выведет ложь
  180.         } else if (string[i] == ')'){                                       // Если же функция закончит проход по строке
  181.             bool--;                                                         // а bool не равен нулю то это тоже ложь
  182.         }                                                                   // Очевидно, что если bool == 0, то функция
  183.         if (bool < 0){                                                      // выведет истину
  184.             return bool;
  185.         }
  186.     }
  187.     return bool;
  188. }
  189.  
  190. int isCorrect(char* string){                                                // Функция проверяет расстановку операторов и чисел в строке
  191.     if (string[0] == '*' || string[0] == '/'){
  192.         printf("Выражение не может начинаться с оператора умножения или деления\n");
  193.         return 0;                                                           // В арифметическом выражении первыми
  194.     }                                                                       // операторы / и * не могут быть первыми
  195.     for (int i = 1; i < strlen(string); ++i) {
  196.         char c = string[i - 1];
  197.         if (c == '(' || c == '+' || c == '-' || c == '*' || c == '/'){      // Проверка на расстановку
  198.             while (i < strlen(string) && string[i] == ' ') i++;          // (следует ли за оператором еще один оператор)
  199.             if ((string[i] < '0' || string[i] > '9') && string[i] != '\0' && string[i] != '('){
  200.                 printf("После оператора не может идти еще один оператор\n");
  201.                 return 0;
  202.             }
  203.         }
  204.     }
  205.     return 1;
  206. }
  207.  
  208. int main(){
  209.     struct tree* node = NULL;
  210.     struct stack* elem = NULL;
  211.     char* str;
  212.     system("clear");                                                // Очистка консольного экрана
  213.     int i, number;
  214.     if (!(str = (char*)malloc(50))) {
  215.         puts("Ошибка при работе с памятью!");
  216.         return 0;
  217.     }
  218.     puts("Введите выражение");
  219.     fflush(stdin);
  220.     fgets(str, 100, stdin);
  221.     if (!isCorrect(str)){                                    // Проверка на расстановку операторов и чисел
  222.         return 1;
  223.     }
  224.     char *exp = (char*) malloc (200 * sizeof(char));
  225.     strcpy(exp, str);
  226.     exp[strlen(exp) - 1] = '\0';
  227.     if (checkBrackets(exp) != 0){                            // Проверка скобок
  228.         printf("Ошибка при расставлении скобок\n");
  229.         return 1;
  230.     }
  231.     str = polish(str, &elem);                                // Обратная польская запись
  232.     i = (int) strlen(str);
  233.     i--;
  234.     while (i >= 0){
  235.         if (*(str + i) == '/' || *(str + i) == '*' || *(str + i) == '-' || *(str + i) == '+'){ // Если знак записываем в дерево
  236.             node = add(node, *(str + i), 0);
  237.             i--;
  238.         }
  239.         if (*(str + i) == ' ') i--;                                // Пропуск пробелов
  240.  
  241.         if (*(str + i) >= '0' && *(str + i) <= '9')                // Встречаем цифру, идем дальше по строке пока число
  242.         {                                                          // не закончится. Записываем число в дерево
  243.             number = 0; int mn = 1;
  244.             while (*(str + i) >= '0' && *(str + i) <= '9')
  245.             {
  246.                 number += (*(str + i) - '0') * mn;
  247.                 mn *= 10;
  248.                 i--;
  249.             }
  250.             node = add(node, ' ', number);
  251.         }
  252.     }
  253.     printf("\nРешение: %s = %d\n", exp, calc(node));                    // Вывод/подсчет результатов
  254.     printf("\nВывод дерева:\n# - пустые узлы дерева\n");
  255.     showTree(node, 0);
  256.     puts("Хотите продолжить\n yes/any key");                            // Рекурсивное меню
  257.     char *userAnswer = (char*) malloc(10 * sizeof(char));
  258.     fflush(stdin);
  259.     fgets(userAnswer, 100, stdin);
  260.     userAnswer[strlen(userAnswer) - 1] = '\0';
  261.     if (strcmp(userAnswer, "yes") == 0) {
  262.         main();
  263.     }
  264.     system("clear");
  265.     return 0;
  266. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement