§ 3. Перагрузка аперацый

Алгоритмические конструкции

Как вам уже известно из курса информатики, любой алгоритм может быть записан с использованием трех базовых алгоритмических конструкций: следование, цикл и ветвление (пример 3.1).

Команды, составляющие алгоритмическую конструкцию следование, выполняются последовательно, друг за другом, в том порядке, в котором они записаны. Команды цикла и ветвления управляют порядком выполнения других команд в программе и относятся к командам управления (управляющим конструкциями).

Алгоритмическая конструкция ветвления обеспечивает выполнение одной или другой последовательности команд в зависимости от истинности или ложности некоторого условия. Оператор ветвления — команда, реализующая алгоритмическую конструкцию ветвления на языке программирования.

Алгоритмическая конструкция повторение (цикл) представляет собой последовательность действий, выполняемых многократно. Саму последовательность называют телом цикла. Оператор цикла — это команда, реализующая алгоритмическую конструкцию повторения на языке программирования.

Существуют разные возможности управлять тем, сколько раз будет повторяться тело цикла. Может быть задано условие продолжения или окончания работы цикла, а также число повторений тела цикла. В зависимости от этого выделяют цикл с предусловием, цикл с постусловием и цикл с параметром.

Существуют разные возможности управлять тем, сколько раз будет повторяться тело цикла. Может быть задано условие продолжения или окончания работы цикла, а также число повторений тела цикла. Выделяют следующие циклы: цикл с предусловием, цикл с постусловием и цикл с параметром. Выбор цикла зависит от задачи. Во многих случаях циклы взаимозаменяемы. При выборе цикла можно ориентироваться на следующее:

  • цикл с параметром используется тогда, когда известно количество повторений;
  • цикл с предусловием используется в том случае, когда известно условие продолжения работы;
  • цикл с постусловием используется тогда, когда тело цикла должно быть выполнено хотя бы один раз.

Пример 3.1 Блок-схемы алгоритмических конструкций.

Следование

Ветвление

Цикл

  • Цикл с параметром (значение параметра изменяется от 1 до N):

  • Цикл с предусловием:

  • Цикл с постусловием:

Кроме блок-схем, для графического представления алгоритмов используют структурограммы (NS-диаграммы, диаграммы Насси — Шнейдермана).

Примеры структурограмм

Команда ветвления:

Команда цикла с предусловием:

Практыкаваннi

 

1. Для праграмы з прыкладу 3.5 выканайце наступнае:

    1. Дапоўніце апісанне класа, прыведзенае ў прыкладах 3.7 і 3.9, перагрузкай аператараў уводу і вываду.
    2. Змяніце функцыі для перагрузкі аператараў параўнання так, каб яны былі дружалюбнымі.
    3. Як будзе рэагаваць праграма, калі выкарыстоўваць знак «<»  для параўнання даўжынi вектараў? Чаму?
    4. Перагрузіце аперацыі «<» і «!=». 
    5. Перагрузіце аператар «*» яшчэ раз, лічачы, што ён выкарыстоўваецца і для знаходжання скалярнага памнажэння двух вектараў [1].


[1] Скалярным памнажэннем двух вектараў   i   з'яўляецца лік .

2. Для праграмы з прыкладу 3.6 выканайце наступнае:

    1. Рэалізуйце шматфайлавы праект, падзяліце аб'яву і вызначэнне класа. Стварыце файлы Matrix.h і Matrix.cpp.
    2. Дапоўніце апісанне класа перагрузкай аператараў уводу і вываду, прыведзенае ў прыкладах 3.8 і 3.10.
    3. Змяніце функцыі для перагрузкі аператараў параўнання так, каб яны былі дружалюбнымі.
    4. Перагрузіце аперацыю «==», якая будзе вяртаць true, у тым выпадку, калі матрыцы маюць аднолькавыя памеры і false у адваротным выпадку.
    5. * Перагрузіце аператар «*» яшчэ раз, лічачы, што ён выкарыстоўваецца і для знаходжання памнажэння матрыц[1]

      [1] Аб тым, як памнажаць матрыцы, можна пачытаць тут: https://www.webmath.ru/poleznoe/formules_6_6.php.

    6. Прадэманструйце працу метадаў і аператараў апісанага класа.

3. Змяніце апісанне класа Parallelepiped (заданне 4, §2), дадаўшы перагрузку аператараў параўнання паралелепіпедаў па аб'ёме.

4. Дадайце ў клас Rect (заданне 6, §2) перагрузку аперацый «+» для атрымання найменшага прамавугольніка, які змяшчае два зададзеных прамавугольніка, і «*» — для атрымання прамавугольніка, які з'яўляецца агульнай часткай (перасячэннем) двух прамавугольнікаў.

5. Стварыць клас Drob. Канструктар прымае два лікі: лічнік і назоўнік дробу. Перагрузіць аперацыі: складанне, множанне, дзяленне, адніманне. Рэалізаваць метады: скарачэнне (выкарыстоўваць private функцыю для знаходжання НОД па алгарытме Еўкліда), пераклад звычайнага дробу ў дзесятковы. Прадэманстраваць працу ўсіх функцый класа і перагружаных аперацый на прыкладах.

6. Стварыць базавы клас Progressii і яе наследнікаў — арыфметычную і геаметрычную прагрэсіі. Рэалізаваць метады: n-ы член прагрэсіі, праверка прагрэсіі на спаданне. Перагрузіць аперацыі: «+» (першы аперанд — пераменная тыпу прагрэсіі, другі — лік (колькасць элементаў)) для вылічэння сумы арыфметычнай прагрэсіі «*» — аналагічна для вылічэння сумы геаметрычнай прагрэсіі. Прадэманстраваць працу ўсіх функцый класа і перагружаных аперацый на прыкладах.

7. Апісаць клас Polinom для працы з мнагачленамі. Палямі класа з'яўляецца ступень мнагачлена і масіў каэфіцыентаў. Перагрузіць аперацыі «+», «-», «*», а таксама ўвод і вывад мнагачлена. Рэалізаваць метад вылічэння значэння мнагачлена для зададзенага значэння пераменнай[1]. *Выкарыстоўваючы метад двайковага дзялення, знайсці корань мнагачлена на зададзеным прамежку (корань павінен быць на гэтым прамежку адзіным).

[1] Рэкамендуецца выкарыстоўваць для вылічэння значэння мнагачлена схему Горнэра — https://intuit.ru/studies/professional_retraining/941/courses/67/lecture/1966?page=2

8*. Апісаць клас BigNumber для працы з «вялікімі» лікамі (лікі, якія не змяшчаюцца ў стандартныя тыпы). Перагрузіць аперацыі «+», «-», «*», параўнання, уводу і вываду.

Прыклад апісання некаторых членаў класа:

///Клас "вялікi лік", апісвае спосаб захоўвання вялікага ліку і складанне

class BigNumber

{

private:

    vector < int > cifr;

///нармалізацыя ліку мадэлюе перанос у наступны разрад, калі лічба > 10

    void norm();

public:

///Канструктар па змоўчанні ("пусты" лік)

    BigNumber() {};

///Канструктар, канвертуе радок у вялікi лік

    BigNumber(string str)

 

    BigNumber operator + (const BigNumber &);

    friend ostream & operator << (ostream &, const BigNumber &);

};

BigNumber::BigNumber(string str)

{

   ///Запісваем лічбы з канца радка

   for (int i = str.size() - 1; i >= 0; i --)

     cifr.push_back(str[i] - '0');

}

 

///Аператар +, выконвае складанне вялікіх лікаў

BigNumber BigNumber::operator + (const BigNumber &num)

{

    BigNumber res;

    int r1 = min(cifr.size(), num.cifr.size());

    res.cifr.resize(r1);

/// складанне лічбаў

    for (int i = 0; i < r1; i++)

        res.cifr[i] = cifr[i] + num.cifr[i];

///калі ў адным з лікаў лічбы скончыліся

    for (int i = r1; i < cifr.size(); i++)

        res.cifr.push_back(cifr[i]);

    for (int i = r1; i < num.cifr.size(); i++)

        res.cifr.push_back(num.cifr[i]);

    res.norm();

    return res;

}

 

void BigNumber::norm()

{

  if (cifr.size() > 1) {

    for (int i = 0; i < cifr.size()-1; i++) {

       cifr[+ 1] += cifr[i] / 10;

       cifr[i] =  cifr[i] % 10;

    }

    if (cifr[cifr.size() - 1] >= 10) {

      int t = cifr[cifr.size() - 1] / 10;

      cifr[cifr.size() - 1] = cifr[cifr.size() - 1] % 10;

      cifr.resize(cifr.size() + 1);

      cifr[cifr.size()-1] =  t;

    }

  }

}

 

///Перагрузка аператара << для вываду

ostream & operator << (ostream &cout_bn,  const BigNumber &num)

{

    for (int i = num.cifr.size() - 1; i >= 0; i--)

        cout_bn << num.cifr[i];

}

 

Прыклад выкарыстання:

int main() {

    BigNumber n1("9999999999999999");

    BigNumber n2("1");

    cout << n1 << endl;

    cout << n2 << endl;

    BigNumber n3 = n1 + n2;

    cout << n3 << endl;

    return 0;