Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс лекцый для 1 курса-1 семестр.doc
Скачиваний:
3
Добавлен:
09.11.2019
Размер:
2.95 Mб
Скачать

Аптымізацыя цыклаў

Існуюць некаторыя агульныя прыёмы аптымізацыі цыклаў:

1. Вынясенне інварыянтных частак з цела цыкла (а гэта тыя пад­вы­ра­зы, значэнні якіх не змяняюцца ўнутры цыкла).

2. Замена больш доўгіх па часе падліку аперацый на больш хуткія.

Прыклад.

Зыходная аперацыя ў цыкле

Аптымізаваная аперацыя ў цыкле

i := i + 1

inc(i)

i := i – 2

dec(i, 2)

2 * i + 1

k, дзе k = 1, 3, …

x * x * x* x * x

sqr(sqr(x)) * x

але x * x * x* x * x больш аптымальная для падліку x5, чым exp(5*ln(x))

3. Аднаразовае вылічэнне аднолькавых падвыразаў або эканомія вы­ра­заў.

Прыклад. Калі ў цыкле неаднаразова выкарыстоўваецца выраз (x + 1), тады карысна ўвесці дапаможную пераменную y, якой надаць зна­чэнне x + 1 і далей выкарыстоўваць y.

4. Выключэнне дзеянняў над канстантамі ў целе цыкла.

Прыклад. Канстантныя выразы 1/4; exp(–2) /5 і г. д. лепш падлічыць да ўваходу ў цыкл.

5. Выкарыстанне вынікаў папярэдняга кроку цыкла. Гэта самы ас­ноў­ны прыём.

Задача. Саставіць эфектыўную праграму падліку шчаслівых білетаў ся­род шасцізначных, васьмізначных і інш.

Рашэнне. Першы алгарытм. Вылучым пераменныя i, j, k, l, m, n, зна­чэн­ня­мі якіх будуць лічбы 0  i  9. Білет шчаслівы, калі i + j + k = l + m + n.

Эўрыстычны падыход прыводзіць да наступнага алгарытму:

PROGRAM Heppy_Ticket_1;

VAR

i, j, k, l, m, n : Byte;

Count : Word;

BEGIN

Count :=0;

FOR i := 0 TO 9 DO

FOR j := 0 TO 9 DO

FOR k := 0 TO 9 DO

FOR l := 0 TO 9 DO

FOR m := 0 TO 9 DO

FOR n := 0 TO 9 DO

IF i + j + k = l + m + n THEN Inc(Count);

Writeln('колькасць=', Count); Readln;

END.

Надрукуецца 55252.

Аналіз. Шэсць укладзеных цыклаў здзяйсняюць перабор усіх ва­ры­ян­таў, іх 106 – мільён, а знайшлі 1/18 частку ўсяго перабору. Ясна, што гэ­та ня­тан­ны алгарытм, неэфектыўны па часе выканання і непры­ста­са­ваны для бі­ле­таў з іншай разраднасцю.

Распрацуем другі алгарытм, заснаваны на іншым падыходзе. Будзем пад­ліч­ваць, колькі разоў атрымаецца сума лічбаў, роўная 0, 1, 2, ..., 3  9, у ад­ной палавіне і ў другой.

PROGRAM Heppy_ticket_2;

VAR i, j, k : Byte;

Count : Word;

a : ARRAY[0..9*3] OF Word;

BEGIN

Count :=0;

FOR i := 0 TO 27 DO a[i] :=0;

FOR i := 0 TO 9 DO

FOR j := 0 TO 9 DO

FOR k := 0 TO 9 DO

Inc(a[i+j+k]);

FOR i := 0 TO 27 DO

BEGIN a[i] := a[i] * a[i];

Count := Count + a[i];

END;

Writeln('колькасць=', Count); Readln;

END.

У гэтым варыянце зэканомілі час (прыкладна ў 20 разоў), але крыху ад­ня­лі памяці. Недахоп праграмы ў тым, што яна разлічана на шас­ці­разрадныя лікі. Калі ж трэба зрабіць падлік для нумароў, разраднасць якіх розная і можа быць вядома толькі ў час выканання праграмы, тады можна інакш запраграміраваць нашы ўкладзеныя цыклы.

Гэта можна зрабіць па прынцыпу «спідометра». Праімітуйце работу спі­до­мет­ра, напрыклад чатырохразраднага. Заўважаеце, што гэта схема ра­бо­ты ўкладзеных цыклаў? Прыменім прынцып «спідометра» і па­леп­шым па­пя­рэд­нюю праграму.

PROGRAM Heppy_ticket_3;

CONST

k=4; {2*k разрадныя лікі}

VAR

i : Byte;

Sum_Digit : Byte;

Count : Longint;

a : ARRAY[0..9*k] OF Word;

Cp : ARRAY[0..k] OF Byte;

BEGIN

FOR i := 0 TO k * 9 DO a[i] := 0;

{колькасць магчымых сум лічбаў}

FOR i := 0 TO k DO Cp[i] := 0;

{занулілі спідометр}

{Cp[0] := 1 спідометр перапоўнены}

REPEAT

Sum_Digit := 0;

FOR i := 1 TO k DO

Sum_Digit := Sum_Digit + Cp[i];

{падлічылі бягучую суму лічбаў

на спідометры}

Inc(a[Sum_Digit]);

i := k;

{пераходзім на наступную

камбінацыю лічбаў спідометра}

WHILE Cp[i] = 9 DO

BEGIN

Cp[i] := 0;

Dec(i);

END;

{скінуўшы ўсе лічбы 9 у канцы

спідометра, дададзім 1

у патрэбную пазіцыю}

Cp[i] := Cp[i] + 1;

UNTIL Cp[0] = 1;

Count := 0;

FOR i := 0 TO k*9 DO

BEGIN a[i] := a[i] * a[i];

count := count + a[i];

END;

Writeln('колькасць=', Count);

Readln;

END.

Заўвагі. Для захавання паслядоўнасці лічбаў спідометра вы­ка­рыс­та­лі масіў Cp[i], i = 0 ... k, у элементах якога запісваецца бя­гу­чы набор лічбаў. Для пераходу да наступнага варыянта трэба дадаць 1 да k-й (апошняй) лічбы ліку. Але гэта можна зрабіць толькі тады, калі яна не роўная 9. Калі лічба 9, то тады трэба скінуць у 0 і дадаць 1 да па­пя­рэд­няй; калі яна не роўная 9 – па папярэдняму прынцыпу. Так працуем да той пары, пакуль не знойдзем лічбу . Паслядоўнасць будзе апош­няй, бо па нашым алгарытме атрымаем , а гэта прымета за­кан­чэн­ня цыкла.