Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C _Учебник_МОНУ

.pdf
Скачиваний:
199
Добавлен:
12.05.2015
Размер:
11.12 Mб
Скачать

Програмування базових алгоритмів

149

{for(i = 1, f = 1; i <= 2 * k - 1; i++) f *= i; u = pow(-1, k)*pow(x, 2 * k) / (2 * k * f);

Memo1->Lines->Add(IntToStr(k)+")"+FormatFloat("0.00000",u)); y += u;

k++;

}

while (fabs(u) >= eps) ; Edit3->Text = FloatToStr(y); Edit4->Text = IntToStr(k – 1);

}

Вигляд цієї форми не буде відрізнятися для кожного з наведених способів розвязання цієї задачі.

Д р у г и й с п о с і б р о з в ‟ я з а н н я

Для того щоб зробити алгоритм програми більш оптимальним, його можна вдосконалити, але для цього слід обчислити рекурентний множник. Це дозволить в даній програмі позбавитись від вкладеного циклу для обчислення факторіала. Зупинимось більш докладно на виведенні рекурентної формули.

 

 

 

 

 

 

 

 

 

 

 

1

x

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k

 

2k

 

 

Подамо

суму ряду

y

 

 

 

 

 

 

 

у вигляді y uk ,

 

2k (2k 1)!

 

 

 

 

 

 

 

 

 

 

k 1

k 1

де uk

 

1 k x2k

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

. Рекурентний множник R – це співвідношення двох поряд ро-

 

 

 

 

2k(2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

зташованих членів ряду:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

u2 R u1 ,

u3 R u2 , …, uk R uk 1 ,

uk 1 R uk ,

звідки

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

R

 

uk

 

або

R

uk 1

 

.

 

 

 

 

 

 

 

 

uk 1

uk

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Тобто можна обчислити рекурентний множник зі співвідношення з попереднім членом ряду або зі співвідношення з наступним членом ряду. Наведемо обидва різновиди обчислення рекурентного множника.

150

Розділ 4

1 р і з н о в и д о б ч и с л е н н я р е к у р е н т н о г о м н о ж н и к а

 

Для визначення R до формули

R

u

k

 

слід підставити uk

 

1 k x2k

та

 

 

 

 

 

 

 

 

uk 1

 

2k(2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

uk 1 . Для обчислення uk 1

 

підставимо до виразу для uk

(k – 1) замість k:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k 1

2(k 1)

 

 

 

 

k 1

 

2(k 1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

x

 

 

 

 

 

 

1

x

 

 

 

 

 

 

 

 

 

 

 

 

 

u

 

 

 

 

 

 

 

 

 

=

 

 

;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k 1

 

 

 

2(k 1)(2(k 1) 1)!

 

 

2(k 1)(2k 3)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 k x2k

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

R

u

k

=

 

 

 

2k (2k 1)!

 

 

=

( 1)k x2k (2k 2) (2k 3)!

=

 

 

 

 

 

 

2(k 1)(2k 3)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

uk 1

 

( 1)k

1 x2k 2

2k (2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 k 1 x2(k 1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

( 1)k k 1 x2k (2k 2)

(2k 2)

 

 

 

 

 

 

1 2 ... (2k 3)

 

 

 

 

 

 

 

x2

 

=

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

=–

 

 

 

 

 

.

 

 

 

 

2k

 

 

 

 

 

 

 

 

 

1 2

... (2k 3) (2k 2) (2k 1)

 

 

2k(2k 1)

 

Окрім рекурентного множника R, треба обчислити перший член ряду за k = 1:

u 1 1 x2

=

x2

.

 

1

2(2

1)!

2

 

 

 

Т е к с т п р о г р а м и

void __fastcall TForm1::Button1Click(TObject *Sender) { float x, y, u, r, eps; int i, f, k = 1;

Memo1->Clear();

x = StrToFloat(Edit1->Text); eps = StrToFloat(Edit2->Text); u = –x*x/2;

y = u; Memo1->Lines->Add(IntToStr(k)+")"+FormatFloat("0.00000",u)); do

{k++;

r = –x*x/(2*k*(2*k-1)); u *= r ;

Memo1->Lines->Add(IntToStr(k)+")"+FormatFloat("0.00000",u)); y += u;

} while(fabs(u)>=eps);

Edit3->Text=FloatToStr(y); Edit4->Text=IntToStr(k);

}

2 р і з н о в и д о б ч и с л е н н я р е к у р е н т н о г о м н о ж н и к а

Для визначення R до формули R

u

k 1

 

слід підставити u

 

 

1 k x2k

 

та

uk

k

2k(2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

uk 1 . Для обчислення uk 1

підставимо до виразу для uk

(k + 1) замість k:

 

u

1

x

2( k 1)

 

=

1

x

;

 

 

 

 

 

 

k 1

 

 

 

 

 

k 1

 

2( k 1)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

k 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2(k 1)(2(k

1) 1)!

2(k 1)(2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Програмування базових алгоритмів

 

 

151

 

 

 

 

 

 

 

1 k 1 x2( k 1)

 

 

 

 

 

 

 

 

 

R

uk 1

=

 

2(k 1)(2k 1)!

=

( 1)k 1 x2k 2 2k (2k 1)!

=

 

 

 

 

 

 

 

1 k

 

 

 

 

 

 

 

u

k

 

 

x2 k

( 1)k x2k 2(k 1) (2k 1)!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2k (2k 1)!

 

 

 

 

 

 

 

=

( 1)k 1 k x2k 2 2k k

 

 

1 2 ... (2k 1)

=–

x2

 

.

(k 1)

 

 

 

 

 

... (2k 1) 2k (2k 1)

 

 

 

 

 

 

 

 

1 2

 

2(k 1)(2k 1)

Окрім рекурентного множника R, треба обчислити перший член ряду за k = 1:

u 1 1 x2

=

x2

.

 

1

2(2

1)!

2

 

 

 

Т е к с т п р о г р а м и

void __fastcall TForm1::Button1Click(TObject *Sender)

{ float x, y, u, r, eps;

int i, f, k = 1;

Memo1->Clear();

 

x = StrToFloat(Edit1->Text); eps = StrToFloat(Edit2->Text); u = –x*x/2;

y = u; Memo1->Lines->Add(IntToStr(k)+")"+FormatFloat("0.00000",u)); do

{r = –x*x/(2*(k+1)*(2*k+1)); u *= r ;

Memo1->Lines->Add(IntToStr(k)+")"+FormatFloat("0.00000",u)); y += u;

k++;

} while(fabs(u)>=eps);

Edit3->Text=FloatToStr(y); Edit4->Text=IntToStr(k);

}

Приклади консольних програм із застосуванням циклів while та do-while

Приклад 4.53 Обчислити квадрати натуральних чисел від 1 до 10 трьома варіантами, використовуючи різні оператори циклу.

Розв‟язок. Оскільки натуральні числа – це цілі додатні числа 1, 2, 3, 4, ..., доцільно використати змінну i як параметр циклу, яка змінюватиметься від 1

до 10.

Уциклі десятиразово повторюватимуться такі дії:

обчислення квадрату числа i;

виведення на екран значення змінної і та її квадрату;

збільшення змінної і на 1.

Текст програми з циклом for:

#include <iostream.h> #include <conio.h>

//------------------------------------------------------------

int main()
{ int i=1, x; while(i<=10) {x = i * i;

152

Розділ 4

int main(int argc, char* argv[]) {int i, x;

for(i=1; i<=10; i++)

{x = i * i;

cout << "Квадрат числа " << i << " дорівнює " << x << endl;

}

getch(); return 0;

}

Результат виконання програми:

Квадрат числа 1 дорівнює 1 Квадрат числа 2 дорівнює 4 Квадрат числа 3 дорівнює 9 Квадрат числа 4 дорівнює 16 Квадрат числа 5 дорівнює 25 Квадрат числа 6 дорівнює 36 Квадрат числа 7 дорівнює 49 Квадрат числа 8 дорівнює 64 Квадрат числа 9 дорівнює 81 Квадрат числа 10 дорівнює 100

Напишемо цю програму з циклами while та do-while замість for. Перше значення змінної і слід задати до циклу. Також слід пам‟ятати, що умовні оператори циклу не збільшують автоматично значення параметра, а тому збільшення параметра слід прописати у тілі циклу.

Текст програми з циклом while:

// Якщо число не перевищує 10, // обчислюватиметься квадрат його значення

// і виводитиметься число разом із квадратом cout << "Квадрат числа " << i << " дорівнює " << x << endl; i++; // Збільшення змінної циклу на 1

}

getch(); return 0;

}

Текст ідентичної програми з циклом do-while: int main(int argc, char* argv[])

{int i = 1, x; do

{x = i * i;

cout << "Квадрат числа " << i << " дорівнює " << x << endl;

i++;

} while (i <= 10); getch(); return 0;

}

Програмування базових алгоритмів

153

Приклад 4.54 Уводити цілі числа, допоки не буде введене трицифрове число, і обчислити кількість введених чисел та суму чисел, які належать до інтер-

валу [–4, 11).

Розв‟язок. Трицифрове число – це число, модуль якого перебуває поміж 100 та 999. Отже, вираз умови продовження виконання циклу матиме вигляд:

abs(x)<100 || abs(x)>999

Якщо для розв‟язання поставленого завдання застосовувати цикл while, то ще до початку циклу слід знати перше значення змінної х, яка буде вводитись згодом у циклі, або присвоїти x будь-яке нетрицифрове значення до циклу, наприклад, 0, щоб можна було увійти до циклу.

Текст програми з циклом while:

int main()

{ int x=0, k=0, s=0;

while(abs(x)<100 || abs(x)>999) // Допоки число х не є трицифрове,

{cout << "Ввести число: "; cin >> x;

k++;

// збільшується кількість уведених чисел і,

if (x>=–4 && x<11)

// якщо х належить до проміжку [–4, 11),

s += x;

// додається його значення до суми.

}

cout << "Введено чисел: " << k << endl;

cout << "Сума чисел з проміжку [–4, 11): " << s << endl; getch();

return 0;

}

Результат виконання програми:

Ввести число: 4 Ввести число: 8 Ввести число: –1 Ввести число: 3 Ввести число: 9 Ввести число: 54 Ввести число: 2 Ввести число: -87 Ввести число: 4 Ввести число: 443 Введено чисел: 10

Сума чисел з проміжку [–4, 11): 29

У цьому прикладі більш оптимально використовувати цикл do–while, що надасть можливість не хвилюватися стосовно першого значення х – цикл розпочнеться поза всяких умов.

Текст основної програми:

int main()

{ int x, k=0, s=0;

154

Розділ 4

do

 

{ cout << " Ввести число: ";

cin >> x;

k++;

 

if (x>=–4 && x<11) s += x;

} while(abs(x)<100 || abs(x)>999);

cout << " Введено чисел: " << k << endl;

cout << " Сума чисел з проміжку [-4, 11): " << s << endl; getch(); return 0;

}

Приклад 4.55 Генерувати й виводити випадкові числа з проміжку [–5, 10), допоки числа збільшуються. Обчислити середнє арифметичне цих чисел.

Розв‟язок. Для генерування випадкових цілих додатних чисел існує функція random(), а для ініціалізації генератора випадкових чисел – функція randomize() (див. докладніше підрозд. 3.7). Параметром функції random() у дужках зазначається верхня межа чисел. Приміром, для генерування чисел з проміжку [–5, 10) слід записати цю функцію в такий спосіб:

x = random(15) – 5;

Числа мають зростати, тобто кожне наступне має бути більше за попереднє. Ми повинні зберігати попереднє число у певній змінній.

Текст основної програми:

int main()

{ int x, y, s, k = 1;

randomize(); // Ініціалізація генератора випадкових чисел x = random(15) – 5;// Перше випадкове число x cout<<"Число: "<<x<<endl;

s = x;

do{ y = x;

// У циклі запам‟ятовується число x у змінній y,

x = random(15) – 5;// і генерується наступне випадкове число x,

cout<<"Число: "<<x<<endl; // яке виводиться на екран.

if(x>y)

// Порівнюється число з попереднім і, якщо

{ s+=x;

// воно є більше за попереднє, обчислюється сума s

k++; }

// та кількість k таких чисел.

} while(x>y);

// Вихід з циклу відбудеться за умови

 

// введення порівняно меншого числа.

cout << "Кількість чисел: " << k << endl;

cout << "Середнє арифметичне: " << (float) s/k << endl; getch(); return 0;

}

Результати виконання програми:

Число: 0 Число: 6 Число: 8 Число: 5

Кількість чисел: 3 Середнє арифметичне: 4.66667

Програмування базових алгоритмів

155

Приклад 4.56 Написати програму обчислення найбільшого спільного дільника (НСД) двох цілих чисел, тобто реалізувати алгоритм Евкліда.

Текст програми:

#include <stdio.h> #include <conio.h>

//------------------------------------------------------------

int main(int argc, char* argv[])

{printf("\nОбчислення найбільшого спільного дільника"); printf("двох цілих чисел.\n");

printf("Уведіть в один рядок два числа і натисніть <Enter>"); printf("\n -> ");

int nod;

// Найбільший спільний дільник (НДС)

int nl,n2;

// Числа, НСД яких треба обчислити

int r;

// Остача від ділення nl на n2

scanf("%i %i", &nl, &n2) ;

printf("НСД чисел %i і %i - це ", nl, n2); while (nl % n2)

{r = nl % n2; // Остача від ділення nl = n2;

n2 = r;

}

nod =n2; printf("%i\n", nod);

printf("\nДля завершення натисніть <Enter>"); getch();

return 0;

}

Результати виконання програми:

Обчислення найбільшого спільного дільника двох цілих чисел. Уведіть до одного рядка два числа і натисніть <Enter>

-> 121 33

НСД чисел 121 і 33 – це 11

Для завершення натисніть <Enter>

Приклад 4.57 Увести цілі числа до Memo1 і скопіювати парні числа з Memo1 до Memo2 допоки їхня сума не стане більшою за 10.

Розв‟язок. При копіюванні чисел слід зупинитись, якщо вже скопійовано всі числа чи то якщо сума скопійованих чисел є більша за 10.

Наведемо три варіанти розв‟язання, використовуючи три цикли: for, while, do-while.

Текст програми:

// Розв‟язання за допомогою циклу for

void __fastcall TForm1::Button1Click(TObject *Sender) { int x, i, n, S=0;

n=Memo1->Lines->Count;

156

Розділ 4

if(n==0) {ShowMessage ("Введіть числа до Memo1"); return;} Memo2->Clear();

//У циклі умова i<n означає, що в Memo1 ще є числа для зчитування і копіювання;

//умова S<=10 означає, сума чисел, котрі було скопійовано, є менше за 10. for(i=0; i<n && S<=10; i++)

{ x=StrToInt(Memo1->Lines->Strings[i]); if(x%2==0)

{Memo2->Lines->Add(IntToStr(x));

S+=x;

}

}

}

//------------------------------------------------------------

// Розв‟язок за допомогою циклу while

void __fastcall TForm1::Button2Click(TObject *Sender)

{int x, i=0, n, S=0; n=Memo1->Lines->Count; if(n == 0)

{ShowMessage ("Введіть числа до Memo1"); return; } Memo2->Clear();

while(i<n && S<=10)

{x=StrToInt(Memo1->Lines->Strings[i]); if(x%2 == 0)

{Memo2->Lines->Add(IntToStr(x)); S+=x;

}

i++;

}

}

//------------------------------------------------------------

// Розв‟язок за допомогою циклу do-while

void __fastcall TForm1::Button3Click(TObject *Sender)

{int x, i=0, S=0, n=Memo1->Lines->Count; if(n == 0)

{ShowMessage("Введіть числа до Memo1"); return;} Memo2->Clear();

do

{x=StrToInt(Memo1->Lines->Strings[i]);

if(x%2 == 0)

{Memo2->Lines->Add(IntToStr(x)); S += x;

}

i++;

}

while (i<n && S<=10);

}

Програмування базових алгоритмів

157

Форма з результатами роботи наведеної програми:

Приклад 4.58 Зчитати числа з Memo, допоки не зустрінеться число зі значенням 0. Віднайти найменше з цих чисел.

Розв‟язок. Для пошуку мінімального числа використовуватимемо такий алгоритм:

1)поточному мінімуму присвоїти перше число;

2)пройти всіма числами і, якщо зустрінеться число, більше за поточний мінімум, присвоїти це число поточному мінімуму.

Після того, як всі числа переглянуто, поточний мінімум можна вважати за остаточний мінімум.

Текст програми:

void __fastcall TForm1::Button1Click(TObject *Sender) { float min, x;

int i=0, n=Memo1->Lines->Count;

x= StrToFloat(Memo1->Lines->Strings[0]); // Вважатимемо, що перше число – мінімальне

min = x;

while(x != 0 && i < n) {i++;

x=StrToFloat(Memo1->Lines->Strings[i]); if(x < min ) // Якщо віднайшли менше число,

min = x; // записати це число у min

}

Edit1->Text = FloatToStr(min);

}

158

Розділ 4

Приклад 4.59 Зчитати числа з Memo, допоки не зустрінеться 0. Віднайти мінімальне додатне число.

Розв‟язок. Відмінність цього прикладу від попереднього полягає в тому, що мінімальне число треба віднайти з-посеред додатних чисел і присвоїти поточному мінімуму перше число не можна, оскільки воно може бути від‟ємним.

Розглянемо два способи розв‟язання цього завдання. П е р ш и й с п о с і б

Спочатку пройдемо по числах в Memo1 і відшукаємо перше додатне число (за допомогою циклу do-while). Після цього пройдемо по решті чисел і віднайдемо мінімальне з додатних.

void __fastcall TForm1::Button1Click(TObject *Sender)

{float min, x;

int i=0, n=Memo1->Lines->Count;

do

{x=StrToFloat(Memo1->Lines->Strings[i]); i++;

}

while(x<=0 && i<n); min = x;

while(x != 0 && i<n)

{x=StrToFloat(Memo1->Lines->Strings[i]); if(x>0 && x<min) min = x;

i++;

}

Edit1->Text=FloatToStr(min);

}

Д р у г и й с п о с і б

Спочатку присвоюємо змінній min значення 0. Зчитуємо числа з Memo. Якщо число є від‟ємне, зігноруємо його. Якщо число є додатне та min=0, це означає, що ще не зустрічалось додатних чисел, це – перше і його слід присвоїти min. Якщо число є додатне і min 0, це означає, що додатні числа вже зустрічались і min вже має певне додатне значення (тимчасовий мінімум). В цьому разі порівнюємо число з min і, якщо воно є менше за min, присвоюємо його.

void __fastcall TForm1::Button1Click(TObject *Sender) { float min=0, x; int i=0,n=Memo1->Lines->Count;

do

{x=StrToFloat(Memo1->Lines->Strings[i]); if(x>0)

if(min==0 || x<min) min = x;

i++;

}

while(x != 0 && i<n); Edit1->Text=FloatToStr(min);

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]