zodiak1

DSA_PracticalTask_1

Feb 16th, 2022 (edited)
234
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.96 KB | None | 0 0
  1. #include <conio.h>
  2. #include <stdio.h>
  3. #include <locale.h>
  4. #include <windows.h>
  5.  
  6. /// <summary>
  7. /// Структура представляет собой модель одночлена.
  8. /// </summary>
  9. struct term {
  10.    term(UCHAR _n = 0, float _a = 0, term *_next = NULL) : n(_n), a(_a), next(_next) { }
  11.  
  12.    /// <summary>
  13.    /// Степень.
  14.    /// </summary>
  15.    UCHAR n;
  16.    /// <summary>
  17.    /// Коэффициент.
  18.    /// </summary>
  19.    float a;
  20.    /// <summary>
  21.    /// Указатель на следующий одночлен полинома.
  22.    /// </summary>
  23.    term *next;
  24. };
  25.  
  26.  
  27. /// <summary>
  28. /// Функция возвращает знак числа.
  29. /// </summary>
  30. /// <param name="n">Число, у которого нужно определить знак.</param>
  31. /// <returns>'+' или '-'.</returns>
  32. char sign(float n);
  33.  
  34. /// <summary>
  35. /// Функция возвращает модуль числа.
  36. /// </summary>
  37. /// <param name="n">Число.</param>
  38. /// <returns>Модуль числа.</returns>
  39. float abs(float n);
  40.  
  41. /// <summary>
  42. /// Выводит полином на консоль.
  43. /// </summary>
  44. /// <param name="p">Указатель на первый одночлен полинома.</param>
  45. /// <param name="c">Имя полинома.</param>
  46. void printPolynomial(term *p, char c);
  47.  
  48. /// <summary>
  49. /// Функция складывает 2 полинома друг с другом.
  50. /// </summary>
  51. /// <param name="a">Указатель на первый полином.</param>
  52. /// <param name="b">Указатель на второй полином.</param>
  53. /// <returns>Указатель на полином, который будет результатом сложения первого и второго полиномов.</returns>
  54. term * addPolynomials(term *a, term *b);
  55.  
  56. /// <summary>
  57. /// Функция считывает из определенного файла 2 полинома.
  58. /// </summary>
  59. /// <param name="path">Путь к файлу.</param>
  60. /// <param name="p">Указатель на указатель, в который нужно записать первый одночлен одного полинома.</param>
  61. /// <param name="q">Указатель на указатель, в который нужно записать первый одночлен другого полинома.</param>
  62. void scanPolynomials(const char *path, term **p, term **q);
  63.  
  64.  
  65. int main()
  66. {
  67.    setlocale(0, "");
  68.    
  69.    term *P = new term(), *Q = new term(), *R;
  70.    
  71.    scanPolynomials("D:/polynomials.txt", &P, &Q);
  72.    R = addPolynomials(P, Q);
  73.  
  74.    printPolynomial(P, 'P');
  75.    printPolynomial(Q, 'Q');
  76.    printPolynomial(R, 'R');
  77.  
  78.    return 0 * _getch();
  79. }
  80.  
  81. void scanPolynomials(const char *path, term **p, term **q)
  82. {
  83.    FILE *stream;
  84.    fopen_s(&stream, path, "r");
  85.  
  86.    if (stream)
  87.    {
  88.       // sign нужен для определения знака коэффициента, end - "флаг", обозначающий, что полином прочитан в файле до конца, если end = '\n'.
  89.       char sign = '+', end = ' ';
  90.      
  91.       float a = 0;          // Коэффициент только что прочитанного одночлена.
  92.       UCHAR N = 0, n = 0;   // N - наибольшая степень одночлена любого полинома, n - степень только что прочитанного одночлена.
  93.  
  94.       bool p_end = false;   // Означает, что полином p построен.
  95.       // r - указатель, с помощью которого осуществляется доступ к каждому одночлену полинома p или q. Читаем каждый одночлен полиномов отдельно, пока не дойдем до конца файла (EOF).
  96.       for (term *r = new term(); fscanf_s(stream, " %c %fx^%hhi%c", &sign, 1, &a, &n, &end, 1) != EOF; )
  97.       {
  98.          // Если степень у прочитанного одночлена больше ранее зафиксированной, то зафиксировать эту степень, как новый максимум.
  99.          if (N < n) N = n;
  100.          // Если перед одночленом стоит знак '-', отрицаем коэффициент.
  101.          if (sign == '-') a *= -1;
  102.          
  103.          // Если первый одночлен полинома меньше n, то в полином нужно добавить этот одночлен с большей степенью в самое начало полинома.
  104.          if (n > r->n)
  105.          {
  106.             // Добавляем новые одночлены в полином на первое место, пока не добавим тот, чья степень стала максимальной для этого полинома.
  107.             for ( ; r->n != n; ) r = new term(r->n + 1, 0, r);
  108.             // Совершен переход к нужному одночлену, прибавляем его коэффициент. *Такой способ задания коэффициента (+=) для одночлена позволяет складывать подобные одночлены.
  109.             r->a += a;
  110.          }
  111.          else // Иначе, значит, что прочитанный одночлен имеет равную или меньшую степень относительно первого одночлена полинома.
  112.          {
  113.             term *t = r;                       // Указатель нужен, чтобы не сбить ссылку на первый одночлен у r.
  114.             for ( ; t->n != n; t = t->next);   // Перемещаемся по полиному r от начала до одночлена со степенью равной n.
  115.             t->a += a;                         // Совершен переход к нужному одночлену, прибавляем его коэффициент.
  116.          }
  117.          // Если уже дочитали до конца первого полинома, говорим, что первый полином построен, и переназначаем r, чтобы заполнять второй полином.
  118.          if (end == '\n' && !p_end)
  119.          {
  120.             p_end = true;
  121.             r = new term();
  122.          }
  123.          p_end ? *q = r : *p = r; // Обновляем полином p или q, в зависимости от того, заполнен ли уже полином p.
  124.       }
  125.  
  126.       // Если степень одного из полиномов (p1) больше, чем степень другого (p2), то добавляем одночлены в начало полинома p2, пока степень p2 < p1.
  127.       for (term **z = (*p)->n < N ? p : (*q)->n < N ? q : NULL; z && (*z)->n < N; )
  128.          *z = new term((*z)->n + 1, 0, *z);
  129.  
  130.       fclose(stream);
  131.    }
  132. }
  133.  
  134. term * addPolynomials(term *a, term *b)
  135. {
  136.    // Указатель на первый элемент полинома суммы.
  137.    term *r = new term();
  138.    // На каждой итерации переходит к следующему элементу каждого полинома, пока не дойдет до последнего, у которого указатель на следующий равен NULL.
  139.    for (term *p = r; a; p = p->next, a = a->next, b = b->next)
  140.    {
  141.       p->n = a->n;
  142.       p->a = a->a + b->a;
  143.       p->next = a->next ? new term() : NULL;
  144.    }
  145.  
  146.    return r;
  147. }
  148.  
  149. void printPolynomial(term *p, char c)
  150. {
  151.    bool f = false; // Индикатор "есть одночлен перед текущим".
  152.    printf_s("%cn(x) = ", c);
  153.    for ( ; p; p = p->next)
  154.    {
  155.       if (p->n && p->a) // Если степень != 0 и коэф != 0, то
  156.       {
  157.          if (abs(p->a) != 1) // если |коэф| != 1, то
  158.             // если есть предодночлен, пишем " %с |%а|", иначе пишем "%а".
  159.             f ? printf_s(" %c %g", sign(p->a), abs(p->a)) : printf_s("%g", p->a);
  160.          // иначе, если есть предодночлен пишем " %с ", иначе, "%с".
  161.          else printf_s(f ? " %c " : "%c", sign(p->a));
  162.  
  163.          // если степень больше 1, то пишем "x^%n", иначе - "х".
  164.          p->n > 1 ? printf_s("x^%d", p->n) : printf_s("x");
  165.          f = true;
  166.       }
  167.       else if (!p->n) // иначе, если степень == 0, то
  168.       {
  169.          if (p->a && f) // если коэф != 0 и есть предодночлен, то
  170.             printf_s(" %c %g", sign(p->a), abs(p->a));
  171.          else if(!f) printf_s("%g", p->a); // иначе, если нет предодночлена, "%a".
  172.          printf_s(".\n");
  173.       }
  174.    }
  175. }
  176. char sign(float n)
  177. {
  178.    return n > 0 ? '+' : '-';
  179. }
  180. float abs(float n)
  181. {
  182.    return sign(n) == '-' ? -1 * n : n;
  183. }
Add Comment
Please, Sign In to add comment