Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LAB6.DOC
Скачиваний:
2
Добавлен:
29.10.2018
Размер:
416.77 Кб
Скачать

7 Лабораторна робота. Рекурсiя в мовi сi

Мета роботи: освоїти прийоми складання рекурсивних алгоритмiв i програм на мовi Сi.

Контрольнi питання :

1 ) Що таке рекурсiя?

2 ) Назовiть види рекурсiї.

3 ) Назовiть основнi етапи проектування рекурсивних алгоритмiв.

4 ) Що таке "умова завершення рекурсiї"?

5 ) Назовiть достоїнства i недолiки рекурсивних алгоритмiв.

Рекурсiя як обчислювальний процес є альтернативою методу iтерацiй (послiдовних наближень).

7. 1 Органiзацiя рекурсiї при рiшеннi обчислювальних завдань по методу послiдовних наближень

Розрахунковi формули завдань (номери 1-35) являють iтерацiйнi алгоритми методу послiдовних наближень. Видiляють слiдуючi окремi випадки iтерацiйних процесiв.

7.1.1 Алгоритм обчислення по явно заданiй рекурентнiй формулi

Наприклад, обчислення квадратного кореня

y = =yn+1=1/2 (yn + x/yn ) , n= 0,1,2... (7.1)

з похибкою | yn+1 - y n | < ε. (7.2)

Початкове наближення вираховується так:

x/2, если x>1

y0 = (7.3)

2x, если x<=1

7.1.2 Алгоритм обчислення значення функцiї по формулi разкладання функцiї в ряд

y = ex = 1 + x + x2 + ... + xn .... + ... (7.4)

з точнiстю чергового члена ряду | xn | < ε.

При пiдсумуваннi подiбних рядiв для скорочування обсягу обчислень необхiдно вивести рекурентнi формули.

В даному випадку вони присутнi неявно i дозволяють виразити наступний член ряду через попереднiй:

an = xn ; a n+1 = x n+1 ; (7.5)

a n+1 x

Маємо = ,

a n n+1

звiдкiля одержуємо необхiдну рекурентну формулу:

x

a n+1 = * a n ; (7.6)

n+1

7. 1. 3 Загальний член ряду має бiльш загальний вид

Наприклад, якщо загальний член має вид

x 2n+1

a n = ,

4n2 -1

то його доцiльно представити у виглядi двох множникiв, один з яких обчислюється за рекурентним спiввiдношенням, а iнший - безпосередньо.

Хай Cn = x2n+1 i вираховуємо рекурентно C n+1 = Cn * x .

Тодi

Cn

an+1 = (7.7)

4n2 -1

Управлiння iтерацiйними циклами здiйснюється по заданому значенню похибки обчислень.

Описанi iтерацiйнi процеси необхiдно звести до рекурсивного виклику функцiй в алгоритмiчнiй мовi.

7. 1. 4 Приклад 1

Визначити функцiю y = .

Будуємо iєрархiю функцiй, що дозволить визначити цiльову.

Вводимо визначення функцiй y0, next_y i body_sqrt. Iз (7.3) одержуємо функцiю початкового наближення :

float y0 (float x)

{ return (x>1.0 ? x/2 : x*2);}

Значення наступного члена ряду через попереднiй обчислюється за формулою (7.1) :

float next_y(float x, float yn)

{ return((yn+x/yn)/2);}

Iтерацiйний процес до досягнення заданої точностi обчислень за формулою (7.2) визначаємо:

float body_sqrt (float x, float yn, float ynplus1, float eps)

{if(fabs(ynplus1-yn)<eps)

return(ynplus1);

else

return (body_sqrt (x, ynplus1,next_y(x, ynplus1), eps));

}

На основi одержаної iєрархiї визначень функцiй складаємо визначення цiльової функцiї:

float main_sqrt (float x, float eps)

{ float yn, ynplus1;

yn= y0(x);

ynplus1= next_y(x, y0(x));

return (body_sqrt (x,yn, ynplus1, eps));

}

Це визначення може бути записано з використанням композицiї функцiй:

float main_sqrt (float x, float eps)

{ return (body_sqrt(x, y0(x),next_y(x, y0(x)),eps));

}

Виклик функцiї main_sqrt для значень x=32 i ε=0. 01 має вид:

main ()

{ float y; y=main_sqrt(32.0, 0.01); }

7.1.5 Програма на мовi Сi

#include <stdio.h>

#include <math.h>

/* ========== ФУНКЦIЯ ПОЧАТКОВОГО НАБЛИЖЕННЯ ===== */

float y0(float x)

{ return(x>1.0 ? x/2 : x*2);}

/* === ФУНКЦIЯ ОБЧИСЛЕННЯ СЛIДУЮЧОГО ЧЛЕНА РЯДУ == */

/* ================== ЧЕРЕЗ ПОПЕРЕДНIЙ ============== */

float next_y(float x, float yn)

{ return((yn+x/yn)/2);}

/* === РЕКУРСИВНА ФУНКЦIЯ ОБЧИСЛЕННЯ ЗНАЧЕННЯ Y === */

float body_sqrt (float x, float yn, float ynplus1, float eps)

{ if(fabs(ynplus1-yn)<eps)

return(ynplus1);

else

return (body_sqrt (x, ynplus1, next_y(x, ynplus1), eps )

);

}

/* ======== ФУНКЦIЯ ОБЧИСЛЕННЯ ЗНАЧЕННЯ Y ПО ====== */

/* ================== ЗНАЧЕННЯМ X И EPS ============= */

float main_sqrt (float x, float eps)

{ return (body_sqrt (x, y0(x), next_y(x, y0(x)), eps ));

}

/*==================== ГОЛОВНА ФУНКЦIЯ ============= */

main ()

{ float x, eps, y;

printf("Введiть x=");

scanf("%f", &x);

printf("та eps=");

scanf("%f", &eps);

y=main_sqrt(x, eps);

/* ПОРIВНЯННЯ ЗНАЧЕНЬ ФУНКЦIЇ, ВИЗНАЧЕНОЇ В MAIN_SQRT, */ /* ==================I БIБЛIОТЕЧНОЇ ФУНКЦIЇ (SQRT) =======*/ printf("Значення:\n");

printf("main_sqrt(%f, %f)=%f\n", x, eps, y);

printf(" sqrt(%f, %f)=%f\n", x, eps, y);

getch();

}

7.2 Органiзацiя рекурсiї при рiшеннi завдань обробки даних

Розглянемо органiзацiю таких рекурсивних обчислень на прикладi рiшення слiдуючого завдання: Визначити, чи є рядок st симетричним.

7.2.1. Постановка завдання

7.2.1.1 Початковi данi

n : цiле; {довжина рядка st}

st : рядок [1..n ]; {початковий рядок}

7.2.1.2 Обмеження

довжина (st) 0 ( st - непустий )

7.2.1.3 Результат

повiдомлення: рядок [ 1.. 20 ]; {строка повiдомлень}

7.2.1.4 Зв'язок

Порiвнюємо по парам символи рядка st з iндексами i та j, розмiщенi симетрично щодо його середини:

st

1 2 3 ... n

i j (початковий стан)

i j (наступний крок)

Якщо цi символи (st[i] i st[j]) рiвнi, то "скорочуєїмо" розмiр рядка на один символ лiворуч i праворуч, перемiщаючи iндекси i та j назустрiч одне одному.

Умови завершення рекурсii:

1) Якщо символи з iндексами i та j рiзнi, то перегляд завершений неуспїшно (st не є симетричним);

2) Якщо st [i] та st[j] збiглися, i рядок st парної довжини

st

i j

або рядок st парної довжини

st

i j

i усi попереднi пари символiв спiвпадали, то перегляд завершений успiшно (st є симетричною).

  1. Метод рiшення

j := j - 1

i := i + 1

не_кiнець := iстина st I = st J

доки нi ( i = j або i = j - 1)

не_кiнець := неправда st I st J i не_кiнець )

не_кiнець := iстина

i := 1

j := n

Промiжнi данi:

не_кiнець: логiчне; {ознака: рiвна iстина, якщо попереднi

симетричнi вiдносно середини st пари

символiв спiвпадають}

i : цiле; {iндекс лiвого символа, що порiвнюється}

j : цiле; {iндекс правого символа, що порiвнюється }

  1. Текст програми на мовi Сi

#include <stdio.h>

#include <conio.h>

#define N 20

#define ESC 27

main ()

{/* ================== ВХIДНI ДАНI ================= */

char s[N];

/* ================= ПРОМIЖНI ДАНI =============== */

int i, /*порядковий номер символу, який введений в рядок */

m = 0; /* власне символ, який введений в рядок */

/* ============= прототип допомiжної функцiї sim ========= */

int sim(char *st,int i,int j);

/* ==== ЧАСТИНА АЛГОРИТМУ, ЩО ВИКОНУЄТЬСЯ=====*/

/* введення вхiдного рядка по символам i оформлення рядка */

while (m != ESC)

{ printf("\nВведiть рядок:\n ");

i=0;

do

s[i++] = getchar();

while (s[i-1]!='\n');

s[i-1]='\0'; /* оформлення масиву символiв як рядка */

if (sim(s, 0, strlen(s)-1))

printf("Цей рядок симетричний\n");

else

printf("Цей рядок несиметричний\n");

printf("Для виходу натиснiть ESC, для продовження - ENTER.");

m=getch(); /* продовження введення рядкiв */

}

}

/* === Допомiжна функцiя перевiрки рядка st на симетричнiсть ==*/

int sim(char *st, int i, int j)

{ if ((i==j)||((i==j-1)&&(st[i]==st[j])))

return 1;

else

if ((st[i]==st[j])&&(sim(st, i+1, j-1)==1))

return 1;

else return 0;

}

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