Костюк - Основы программирования
.pdfГлава 3 Алгоритмы с одним основным циклом
3.1 Рекуррентные последовательности и алгоритмы
Определение 3.1. Числовая последовательность {xk} называется рекуррентной
ранга p, если |
|
|
|
ì xk |
= ak , |
k = 0, 1, ..., p -1, |
(3.1) |
í |
= f (k, xk −1 , xk −2 ,..., xk − p ), |
k = p, p + 1, ... |
|
îxk |
|
где a0, a1, …, ap – 1 – константы, а f – функция.
Определение рекуррентной последовательности само является алгоритмом, кото рый надо просто "переписать" на Паскале. Этот алгоритм состоит из присваиваний начальных значений элементам x0, x1, …, xp – 1 и цикла вычисления последующих элементов xk . Доказательство правильности алгоритма строится на основе метода математической индукции или инварианта. Исследование эффективности алгоритма также несложно. Объем требуемой памяти определяется используемыми массивами. Трудоемкость определяется количеством выполнений операторов в цикле и обычно является линейной.
Пример 3.1. Вычисление элементов рекуррентной последовательности (c номера 0 по номер n), заданной формулой (3.1). Массив A с нумерацией элементов от 0 до p-1 содержит константы a0, a1, …, ap . Элементы последовательности будут за писываться в массив X. Функция f представляет собой формулу, в которой исполь зуются элементы массива X с номерами от k-p до k-1.
for k:=0 to p-1 do
X[k]:=A[k]; (3.1) for k:=p to n do
X[k]:= f(k,X);
Доказательство правильности этого алгоритма излишне, достаточно лишь убе диться в том, что алгоритм работает в строгом соответствии с определением рекур рентной последовательности.
Конец примера.
Заметим, что алгоритм (3.1) на самом деле является "полуфабрикатом", во вто рой строчке вместо f(k,X) надо записать конкретную формулу, зависящую от ве личин k,X[k-1],X[k-2],…,X[k-p]. Если требуется вычислить не все n эле
42
ментов последовательности, а только n–й, то можно обойтись без массива, исполь зуя p+1 или даже p вспомогательных переменных.
Пример 3.2. Сумму каких-либо элементов ai можно представить рекуррентной
последовательностью ранга 1: |
|
|
|
|
|
|
ìS0 |
= 0, |
|
|
(3.2) |
í |
= Si−1 + ai , |
i = 1, 2, ..., n . |
|||
|
îSi |
|
|||
Эта последовательность вычисляется алгоритмом: |
|
||||
|
|
|
|
|
|
|
S:=0; |
|
|
|
|
|
for i:=1 to n do |
|
|
(3.2) |
|
|
S:=S+ a(i); |
|
|
|
Здесь a(i) – формула вычисления i–го элемента суммы, зависящая только от i, поэтому достаточно всего одной дополнительной переменной S.
Конец примера.
Полином от x степени n можно представить в виде формулы Горнера:
P (x) = a |
n |
xn + a |
n−1 |
xn−1 + ...+ a x + a |
0 |
= (... |
(a |
n |
x + a |
n−1 |
)x + ...+ a )x + a |
0 |
, |
(3.3) |
n |
|
1 |
|
|
|
1 |
|
|
где an, an–1, …, a1, a0 – коэффициенты полинома.
Пример 3.3. Из формулы (3.3) можно получить следующее рекуррентное соотно шение для вычисления полинома при заданном значении x и коэффициентов a0, a1, …, an :
ìP0 = an , |
|
|
|
(3.4) |
|
íP = P |
x + a |
n−i |
, i = 1, 2, ..., n . |
||
î i |
i−1 |
|
|
|
В свою очередь, вычисления по рекуррентному соотношению (3.4) можно вы полнить алгоритмом:
|
|
|
P:=a[n]; |
|
(3.3) |
for i:=1 |
to n do |
|
P:=P*x+a[n-i]; |
|
Конец примера.
Формулу (3.3) можно трактовать как представление неотрицательного целого числа P(x) в системе счисления с целочисленным основанием x. Тогда алгоритм (3.3) позволяет вычислить значение числа при заданном основании x и наборе цифр a[n], a[n-1], …, a[0] в записи числа.
Пример 3.4. Из формулы (3.3) можно получить другое рекуррентное соотноше ние для вычисления цифр a0, a1, …, an неотрицательного целого числа Pn при задан ном значении основания x:
43
ìai = Pn−i mod x, |
|
|
(3.5) |
||
íP |
= P |
div x, |
i = 0, 1, ..., n, P |
> 0, |
|
î n−i−1 |
n−i |
|
n−i |
|
|
где операция mod есть вычисление остатка от деления, а div – деление с отбрасы ванием остатка. При этом подразумевается, что количество цифр n в представлении числа Pn заранее не известно. Вычисления по рекуррентному соотношению (3.5) можно выполнить алгоритмом:
i:=0; |
|
|
while P>0 do |
|
|
begin |
|
|
a[i]:=P mod x; |
(3.4) |
|
P:=P div x; |
||
|
||
i:=i+1 |
|
|
end; |
|
|
n:=i-1; |
|
Конец примера.
Иногда удается вывести формулу, непосредственно выражающую n-й элемент рекуррентной последовательности. Доказательство правильности такой формулы можно произвести методом математической индукции.
Пример 3.5. Сумма квадратов чисел от 1 до n задается следующей рекуррент ной последовательностью:
ìS0 |
= 0, |
2 |
|
|
(3.6) |
í |
= Sk −1 + k |
, |
k = 1, 2, ..., n , |
||
îSk |
|
|
которая непосредственно вычисляется алгоритмом:
S:=0; |
|
for k:=1 to n do |
(3.5) |
S:=S+k*k; |
|
Как доказано в примере 2.3, для последовательности (3.6) справедлива форму ла (2.1):
Sn = 2n3 + 3n2 + n
6
Конец примера.
Пример 3.6. Числа Фибоначчи задаются следующей рекуррентной последова тельностью ранга 2:
ì f0 |
= 0, f1 |
= 1, |
(3.7) |
í |
= fk −1 + fk −2 , k = 2, 3, ... , |
||
î fk |
|
n–й элемент которой вычисляется следующим алгоритмом:
44
|
|
|
|
f1:=0; f2:=1; |
|
|
for k:=2 to n do |
|
|
begin |
(3.6) |
|
f3:=f2+f1; |
|
|
|
|
|
f1:=f2; f2:=f3 |
|
|
end |
|
Докажем, что для рекуррентной последовательности (3.7) справедлива формула |
||
Муавра |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
æ |
æ |
|
+ |
|
|
|
ön |
|
|
æ |
|
|
|
|
|
|
|
|
ön |
ö |
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||
|
|
|
|
|
|
|
|
|
fn |
= |
|
|
|
|
ç |
ç1 |
|
÷ |
- |
ç |
1- 5 ÷ |
÷ |
|
|
|
|
|
|
|
|||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ç |
ç |
|
2 |
|
|
|
÷ |
ç |
|
2 |
|
|
÷ |
÷ . |
|
|
|
|
|
|
(3.8) |
||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ç |
è |
|
|
|
|
ø |
|
|
è |
|
|
|
ø |
÷ |
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 è |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ø |
|
|
|
|
|
|
|
|||||||||||||
Доказательство. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
Базис. При n = 0 и n = 1 проверяем простой подстановкой в (3.8). |
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Предположение. Пусть при n ≥ 0 формула (3.8) верна. |
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||
Вывод. При n + 1 по формулам (3.7) и (3.8) получаем: |
|
|
|
|
|
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|
|
|
æ |
æ |
|
|
ön |
|
|
æ |
|
|
|
|
|
|
|
|
|
ön |
ö |
|
|
|
|
|
æ |
æ |
|
|
|
|
|
|
|
|
ön−1 |
æ |
|
|
|
ön−1 |
ö |
|
|||||||
|
|
1 |
+ |
|
|
|
|
|
- 5 |
|
|
1 |
|
1 + |
|
|
|
|
1 |
- |
5 |
|
||||||||||||||||||||||||||||||
fn+1 = |
|
ç |
ç1 |
5 ÷ |
|
|
|
ç1 |
÷ |
|
÷ |
|
|
ç |
ç |
|
|
5 ÷ |
|
ç |
÷ |
÷ |
|
|||||||||||||||||||||||||||||
|
|
ç |
ç |
2 |
÷ |
|
- |
ç |
|
|
2 |
|
|
|
÷ |
|
÷ + |
|
|
|
|
ç |
ç |
2 |
÷ |
- |
ç |
|
2 |
|
÷ |
÷ |
= |
|||||||||||||||||||
|
|
5 |
ç |
è |
ø |
|
|
|
è |
|
|
|
|
|
ø |
|
÷ |
|
|
|
5 |
|
ç |
è |
ø |
|
è |
|
|
ø |
÷ |
|
||||||||||||||||||||
|
|
è |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ø |
|
|
|
|
è |
|
|
|
|
|
|
|
|
|
|
ø |
|
||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
æ |
æ |
1+ |
|
|
|
ön+1 |
æ |
|
|
|
|
|
|
|
ön+1 ö |
|
|
|
|
|
|
|
|||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
1 |
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
ç |
ç |
|
|
5 ÷ |
|
|
|
ç1- |
÷ |
÷ |
|
|
|
|
|
|
|
|||||||||||||||||||||||
|
|
|
|
|
|
|
|
= |
|
|
|
ç |
ç |
|
|
|
|
2 |
÷ |
|
|
|
- ç |
|
|
2 |
|
|
|
÷ |
÷ , |
|
|
|
|
|
|
|
||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
5 |
ç |
è |
|
|
|
|
ø |
|
|
|
è |
|
|
|
|
|
ø |
÷ |
|
|
|
|
|
|
|
||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
è |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ø |
|
|
|
|
|
|
|
||||||||||||||||
учитывая, что |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
æ1± |
|
|
|
5 |
ö |
|
= 1+ |
1± |
|
5 |
|
. |
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
ç |
|
|
2 |
|
|
|
÷ |
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
ç |
|
|
|
|
|
÷ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
è |
|
|
|
|
|
|
|
|
|
ø |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
Конец примера. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
a = lim( fk+1 / fk ) = (1+ |
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||
Число |
|
5 |
) / 2 » 1,62 , |
входящее в формулу (3.8), называют |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
k→∞ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
золотым сечением. Заметим, что формулу (3.8) целесообразно применять при доста точно больших n. При этом вычисления необходимо выполнять над вещественны ми, т.е. приближенными числами, а результат округлять до целого. Кроме того, вто рое слагаемое по модулю меньше 0.5, и им можно пренебречь.
В некоторых случаях рекуррентная последовательность может иметь предел при n → ∞. Типичным примером могут служить бесконечные суммы, задаваемые соотно шениями:
ìS0 |
= 0, |
(3.9) |
í |
= Sk −1 + fk , k = 1, 2, ... |
|
îSk |
|
45
в которых слагаемые f k стремятся к нулю при k → ∞. При этом сами слагаемые так же могут задаваться в виде рекуррентной последовательности:
|
ì f1 |
= a, |
|
|
(3.10) |
í |
= p(k, fk −1 ), |
k = 2, 3, ... |
|||
|
î fk |
|
|||
Вычисление предела такой |
последовательности с заданной точностью eps |
||||
можно осуществить следующим алгоритмом: |
|
|
|
||
|
|
|
|
|
|
|
S:=0; f:=a; k:=1; |
|
|
|
|
|
while abs(f)>=eps do |
|
|
||
|
begin |
|
|
|
|
|
S:=S+f; |
|
|
(3.7) |
|
|
f:= p(k, f); |
|
|
|
|
|
k:=k+1 |
|
|
|
|
|
end |
|
|
|
|
Трудоемкость алгоритма, т.е. количество |
k выполнений цикла, определяется из |
||||
формулы f k ≤ ε , где ε – заданная точность вычисления последовательности. |
|
Пример 3.7. Приближенное значение функции |
sin x можно вычислить с помо |
||||||||
щью суммы |
|
|
|
|
|
|
|
|
|
sin x = x - |
x3 |
x5 |
k |
x2k +1 |
|
||||
|
+ |
|
- ...(-1) |
|
|
, |
(3.11) |
||
3! |
5! |
(2k + 1)! |
для которой справедливо рекуррентное соотношение (3.9). Поделив выражение для
fk = (-1) |
k |
x2k +1 |
|
на выражение для |
fk−1 = (-1)k −1 |
x2k −1 |
|
, получим рекуррентное |
|||||||
|
(2k |
+ 1)! |
(2k -1)! |
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|||||
соотношение для элементов суммы: |
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
ì f |
0 |
= x, |
|
|
|
|
|
|
|
|
|
|
|
|
|
ï |
|
|
|
x |
2 |
|
|
|
|
(3.12) |
|
|
|
|
|
í f |
k |
= - f |
k −1 |
|
, |
k = 1, 2, ... |
||||
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
ï |
|
2k(2k +1) |
|
|
|
|
|
|||
|
|
|
|
|
î |
|
|
|
|
|
|
|
|
Вычисление суммы (3.11) с заданной точностью eps записано в виде алгоритма (3.8). Завершимость алгоритма следует из того, что fk → 0 при k → ∞. Доказатель ство правильности алгоритма легко провести методом инварианта.
S:=0; f:=x; k:=1;
while abs(f)>=eps do begin
S:=S+f; (3.8) f:=-f*x*x/(2*k*(2*k+1));
k:=k+1 end
|
|
|
|
|
|
|
|
|
|
|
46 |
Трудоемкость алгоритма (количество |
k выполнений цикла) можно определить |
||||||||||
из формулы |
|
fk |
|
= |
|
x |
|
2k −1 |
≤ ε , где ε – |
заданная точность. Так, например, если | |
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|||||
|
|
(2k −1)! |
|||||||||
|
|
|
|
|
|
|
|||||
x| ≤ 1, то k < log2 1/ε . |
|
|
|||||||||
Конец примера. |
|
|
Для суммы со знакопеременными слагаемыми, как, например, в формуле (3.11), вычисленное значение суммы будет отличаться от истинного значения предела не бо лее чем на величину абсолютного значения первого отброшенного слагаемого. Если же все слагаемые имеют один и тот же знак, то для определения того, сколько слагае мых необходимо суммировать, приходится выводить формулу так называемого «остаточного члена суммы».
Более того, сумма, содержащая слагаемые одного и того же знака, может даже не иметь предела (т.е. быть бесконечной). Для вычисления такой суммы можно напи сать алгоритм, доказать его завершимость, однако на самом деле это не будет иметь никакого отношения к самой сумме.
Пример 3.8. Рассмотрим сумму |
1 |
|
1 |
|
1 |
|
|
|
|
|
S = 1 + |
+ |
+ ... + |
+ ... |
, |
(3.13) |
|||||
2 |
3 |
|
||||||||
|
|
|
k |
|
|
|||||
стремящуюся к бесконечности при k → ∞, хотя |
lim |
1 |
= 0 |
. Алгоритм ее вычисления: |
||||||
|
||||||||||
|
|
|
|
|
k →∞ k |
|
|
S:=0; k:=1;
while (1/k)>=eps do
begin
S:=S+1/k; (3.9) k:=k+1
end
конечен, причем вычисленное значение S будет также конечным. На самом деле S будет зависеть от eps. Например, при eps=10-4 вычисленное значение S≈9,79, а при eps=10-8 значение S≈19. Понятно, что вычислять подобные суммы не име ет никакого смысла.
Конец примера.
Вот еще несколько примеров рекуррентных последовательностей.
Пример 3.9. Рассмотрим рекуррентную последовательность для вычисления квадратного корня заданного числа, которая была известна еще Герону:
47
|
|
|
|
|
|
|
|
|
|
|
ìs0 |
= 1, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
ï |
|
|
|
|
|
|
1 |
æ |
|
|
|
|
a |
ö |
|
|
|
|
|
|
|
|
|
|
|
|
|
(3.14) |
||||||
|
|
|
|
|
|
|
|
|
|
í |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
ï |
s |
k |
= |
|
ç s |
k −1 |
+ |
|
|
|
|
|
÷, k = 1, 2, ... |
|
|
|
|
|
|
|||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
ç |
|
|
|
|
|
÷ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
î |
|
|
|
|
|
|
è |
|
|
|
|
sk −1 ø |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
lim sk = |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
Докажем, что |
|
a |
при a ≥ 0. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||
|
|
|
k→∞ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Доказательство. Пусть sk = |
|
|
|
|
+ ek , где ek – ошибка k–го приближения. Тогда |
|||||||||||||||||||||||||||||||||||||||
|
|
a |
||||||||||||||||||||||||||||||||||||||||||
|
|
|
1 æ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
a |
|
|
|
ö |
|
|
|
|
1 |
|
|
|
|
e2 |
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
s |
k |
= |
ç |
|
a + e |
k −1 |
+ |
|
|
|
|
|
|
|
|
|
|
|
÷ = |
|
|
a + |
|
|
|
× |
|
|
|
|
k−1 |
|
= |
|
a + e |
k |
. |
(3.15) |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||||||||||||||
|
|
ç |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
÷ |
|
|
|
|
2 |
|
|
|
|
a + ek −1 |
|
|
|
|
|
|||||||||
|
|
|
2 è |
|
|
|
|
|
|
|
|
|
|
|
a + ek −1 ø |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||||||
Вычислим e1: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
= 1 (1+ a) - |
|
= |
( |
|
-1)2 |
|
|
|
|
|
|
||||||||||||||||||||||||||
|
|
|
|
e = s - |
|
|
|
|
a |
³ 0 , |
|
|
|
|
|
|||||||||||||||||||||||||||||
|
|
|
|
a |
a |
|
|
|
|
|
||||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||||||||||||||||||||
|
|
|
|
1 |
|
1 |
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|||||
и тогда |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ek = |
1 |
|
|
|
|
|
e2 |
|
³ 0, |
ek £ |
1 |
×ek −1, |
k = 2, ... |
|
|
|
||||||||||||||||||||||||
|
|
|
|
2 × |
|
|
a + ek −1 |
2 |
|
|
|
|||||||||||||||||||||||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
k |
−1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
Полученные неравенства утверждают, что, начиная с |
e1, |
все ek |
|
неотрицатель |
ны, и каждая последующая ошибка меньше предыдущей, по крайней мере, в 2 раза. Т.е. e1/e2 ≥ 2, e1/e3 ≥ 4, …, e1/ek ≥ 2k – 1, откуда:
k £ log2 |
1+ a . |
(3.16) |
|
2ε |
|
Поэтому limk→∞ ek = 0 . Кроме того, начиная с s1 , все sk убывают.
Вычисление предела последовательности (3.14), начиная с s1 , с заданной точно стью eps записано в виде алгоритма (3.10).
s:=(1+a)/2; e:=eps; |
|
|
while e>=eps |
do |
|
begin s1:=(s+a/s)/2; |
(3.10) |
|
e:=s-s1; |
s:=s1 |
|
end |
|
|
Трудоемкость алгоритма, т.е. количество выполнений цикла, определяется фор мулой (3.16).
Конец примера.
Пример 3.10. Пусть на интервале [a, b] задана непрерывная функция y = f(x), причем значения функции на концах интервала f(a) и f(b) имеют разные знаки. Тогда на этом интервале функция имеет хотя бы один корень x0 , такой, что f(x0) = 0. Задача состоит в вычислении корня функции с заданной точностью ε / 2 , т.е. требуется найти такое z, что | x0 – z | ≤ ε / 2 . Дихотомический метод решения этой задачи состоит в том, что на каждом шаге интервал делится пополам и опреде
48
ляется тот из полуинтервалов, где может находиться корень. Можно построить сле дующую рекуррентную последовательность пар чисел {ui , vi}:
ìu0 = a, v
ïíui+1 = ui , ïîui+1 = (ui
0 = b, |
|
|
|
vi+1 = (ui + vi ) / 2, |
при |
signf (ui ) ¹ signf ((ui + vi ) / 2), |
(3.17) |
+ vi ) / 2, vi+1 = vi , |
при |
signf (ui ) = signf ((ui + vi ) / 2), |
|
которая сходится к искомому корню. Алгоритм (3.11) вычисляет ее предел x с за данной точностью eps/2.
u:=a; v:=b; x:=(u+v)/2; while (v-u)>=eps do
begin
if f(u)*f(x)<=0 then v:=x (3.11) else u:=x;
x:=(u+v)/2 end
Трудоемкость алгоритма, т.е. количество выполнений цикла, определяется фор мулой:
é |
b - a ù |
(3.18) |
|
k = êlog2 |
ε |
ú . |
|
ê |
ú |
|
Конец примера.
Пример 3.11. Алгоритм Евклида, вычисляющий наибольший общий делитель НОД(a, b) двух целых чисел a ≥ 0, b ≥ 0, основан на следующих инвариантных со отношениях:
1)НОД(a, 0) = a;
2)НОД(a, b) = НОД(b, a);
3)НОД(a, b) = НОД(a mod b, b), a ≥ b > 0.
Первые два соотношения очевидны. Докажем третье. Во-первых, заметим, что операция r = a mod b эквивалентна многократному вычитанию b из a, до тех пор,
пока не будет выполняться: 0 ≤ r < b. Поэтому достаточно доказать, что НОД(a, b) = НОД(a – b, b), a ≥ b > 0.
Пусть верно противоположное утверждение, а именно:
|
|
|
НОД(a, b) = d, |
НОД(a – b, b) = c, причем c > d. |
|
|
|||
Но тогда |
a − b |
= |
a |
- b , при этом |
|
a − b |
, а также b – оба целые, в то время как |
a |
|
c |
c |
|
c |
c |
|||||
|
|
c |
|
c |
|||||
может быть целым лишь в случае, если |
c = d. Это противоречие и доказывает третье |
||||||||
соотношение. |
|
|
|
|
|
|
|
|
49
Из этих соотношений можно построить такую последовательность пар {xi, yi},
что: НОД(xi, yi) = НОД(a, b), max(xi, yi) > max(xi + 1, yi + 1): |
|
|
|
|
|
|
||||||||||
ìx0 = a, y0 = b, |
|
|
|
|
|
|
|
|
|
|
|
|
||||
ï x |
i+1 |
= x |
i |
mod y |
, |
y |
i+1 |
= y |
, |
при |
x |
i |
³ y |
i |
> 0 |
(3.19) |
ïí |
|
i |
|
|
i |
|
|
|
|
|
|
|||||
î yi+1 |
= yi mod xi , |
xi+1 |
= xi , |
при |
yi |
³ xi |
> 0, |
|
Алгоритм (3.12) вычисляет последовательность (3.19) до тех пор, пока ее можно продолжать (пока обе переменных, как x, так и y, положительны).
x:=a; y:=b;
while (x>0)and(y>0) do
if x>=y then x:=x mod y (3.12) else y:=y mod x;
if x>0 then nod:=x else nod:=y
Трудоемкость алгоритма, т.е. количество выполнений цикла, определяется чис лами a и b. При этом наихудший случай будет, если при
fk ≥ max(a, b) > fk – 1,
– числа последовательности Фибоначчи, выполняется условие max(a, b) = fk , min(a, b) = fk – 1 .
Тогда k – количество выполнений цикла. Пренебрегая вторым слагаемым в (3.8) и логарифмируя левую и правую части, получим:
k » logα (5 fk ) = logα 2×log2 (5 fk ) ,
k £ logα 2 × log2 (5 max(a,b)) » 1.4 × log2 max(a,b) ,
где a = (1+ 5) / 2 .
Конец примера.
3.2 Алгоритмы с упорядоченными массивами
Числовой массив с расположенными по неубыванию или по невозрастанию зна чениями элементов называется упорядоченным. Использование таких массивов поз воляет создавать эффективные алгоритмы решения многих важных задач. Алгорит мы упорядочения (называемые также алгоритмами сортировки) позволяют превра тить неупорядоченный массив в упорядоченный. Примерами таких алгоритмов яв ляются алгоритмы (1.8), (2.6)–(2.8).
Задача слияния двух входных упорядоченных массивов A и B состоит в фор мировании упорядоченного массива C, содержащего все элементы из входных мас
50
сивов. Можно переписать все элементы из массивов A и B подряд, а затем все упо рядочить, однако задачу слияния можно решить более эффективно.
Рассмотрим следующий алгоритм слияния для упорядоченных по неубыванию массивов. Вначале элемент A[1] сравнивается с элементом B[1] и меньший из них переписывается в массив C. Если меньшим был A[1], то на следующем шаге сравниваются A[2] и B[1], а если меньшим был B[1], то будут сравниваться A[1] и B[2] и т.д. При равенстве можно пересылать любой элемент. Если на оче
редном шаге окажется, что из одного входного массива все элементы переписаны в C, то переписывается элемент из другого массива.
Пример 3.12. Алгоритм слияния. Входные массивы A и B содержат соответ ственно n1 и n2 элементов, результирующий массив C будет содержать n1+n2 элементов.
|
i1:=1; i2:=1; |
{1} |
|
|
|
|
for i:=1 to n1+n2 do |
{2} |
|
|
|
|
if i1>n1 then |
{3} |
|
|
|
|
begin |
C[i]:=B[i2]; i2:=i2+1 end |
{4} |
|
|
|
else if |
i2>n2 then |
{5} |
(3.13) |
|
|
begin |
C[i]:=A[i1]; i1:=i1+1 end |
{6} |
||
|
else if |
A[i1]<=B[i2] then |
{7} |
|
|
|
begin |
C[i]:=A[i1]; i1:=i1+1 end |
{8} |
|
|
|
else |
C[i]:=B[i2]; i2:=i2+1 end |
{9} |
|
|
|
begin |
{10} |
|
|
|
Доказательство правильности. Инвариантом цикла будет следующее логиче |
|||||
ское соотношение: |
|
|
|
|
|
|
{C[1],...,C[i-1]}={A[1],...,A[i1-1],B[1],...,B[i2-1]}, |
||||
|
|
C[1]<=C[2]<=...<=C[i-1], |
|
i2<=n2. |
|
|
C[i-1]<=A[i1] при i1<=n1, C[i-1]<=B[i2] при |
Первая строчка в логическом соотношении означает, что набор значений элемен |
|
тов, записанных (на очередном шаге) в массив |
C, совпадает с набором значений |
элементов, переписанных из массивов A и B (но в другом порядке). |
Завершимость алгоритма очевидна, цикл выполнится ровно n1+n2 раз, после его выполнения i=n1+n2+1. Если инвариант справедлив, то после выполнения
цикла в n1+n2 элементах массива C окажутся упорядоченные значения всех эле ментов из A и B.
Для доказательства инварианта необходимо проверить его истинность перед вы полнением цикла, а также истинность при однократном выполнении цикла. Второе доказывается рассмотрением четырех случаев:
1) условие в строчке 3 алгоритма истинно;