work
This commit is contained in:
parent
4c531b5ae7
commit
d4c714cbe1
261 changed files with 7370 additions and 546 deletions
|
@ -0,0 +1,93 @@
|
|||
# Вычисление рекурсией (медленное)
|
||||
|
||||
Решение по формуле, используя рекурсию:
|
||||
|
||||
```js run
|
||||
function fib(n) {
|
||||
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
|
||||
alert( fib(3) ); // 2
|
||||
alert( fib(7) ); // 13
|
||||
// fib(77); // не запускаем, подвесит браузер
|
||||
```
|
||||
|
||||
При больших значениях `n` оно будет работать очень медленно. Например, `fib(77)` уже будет вычисляться очень долго.
|
||||
|
||||
Это потому, что функция порождает обширное дерево вложенных вызовов. При этом ряд значений вычисляется много раз. Например, посмотрим на отрывок вычислений:
|
||||
|
||||
```js no-beautify
|
||||
...
|
||||
fib(5) = fib(4) + fib(3)
|
||||
fib(4) = fib(3) + fib(2)
|
||||
...
|
||||
```
|
||||
|
||||
Здесь видно, что значение `fib(3)` нужно одновременно и для `fib(5)` и для `fib(4)`. В коде оно будет вычислено два раза, совершенно независимо.
|
||||
|
||||
Можно это оптимизировать, запоминая уже вычисленные значения, получится гораздо быстрее. Альтернативный вариант -- вообще отказаться от рекурсии, а вместо этого в цикле начать с первых значений `1`, `2`, затем из них получить `fib(3)`, далее `fib(4)`, затем `fib(5)` и так далее, до нужного значения.
|
||||
|
||||
Это решение будет наиболее эффективным. Попробуйте его написать.
|
||||
|
||||
# Алгоритм вычисления в цикле
|
||||
|
||||
Будем идти по формуле слева-направо:
|
||||
|
||||
```js no-beautify
|
||||
var a = 1, b = 1; // начальные значения
|
||||
var c = a + b; // 2
|
||||
|
||||
/* переменные на начальном шаге:
|
||||
a b c
|
||||
1, 1, 2
|
||||
*/
|
||||
```
|
||||
|
||||
Теперь следующий шаг, присвоим `a` и `b` текущие 2 числа и получим новое следующее в `c`:
|
||||
|
||||
```js no-beautify
|
||||
a = b, b = c;
|
||||
c = a + b;
|
||||
|
||||
/* стало так (ещё число):
|
||||
a b c
|
||||
1, 1, 2, 3
|
||||
*/
|
||||
```
|
||||
|
||||
Следующий шаг даст нам ещё одно число последовательности:
|
||||
|
||||
```js no-beautify
|
||||
a = b, b = c;
|
||||
c = a + b;
|
||||
|
||||
/* стало так (ещё число):
|
||||
a b c
|
||||
1, 1, 2, 3, 5
|
||||
*/
|
||||
```
|
||||
|
||||
Повторять в цикле до тех пор, пока не получим нужное значение. Это гораздо быстрее, чем рекурсия, хотя бы потому что ни одно из чисел не вычисляется дважды.
|
||||
|
||||
P.S. Этот подход к вычислению называется [динамическое программирование снизу-вверх](http://ru.wikipedia.org/wiki/%D0%94%D0%B8%D0%BD%D0%B0%D0%BC%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5).
|
||||
|
||||
# Код для вычисления в цикле
|
||||
|
||||
```js run
|
||||
function fib(n) {
|
||||
var a = 1,
|
||||
b = 1;
|
||||
for (var i = 3; i <= n; i++) {
|
||||
var c = a + b;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
alert( fib(3) ); // 2
|
||||
alert( fib(7) ); // 13
|
||||
alert( fib(77) ); // 5527939700884757
|
||||
```
|
||||
|
||||
Цикл здесь начинается с `i=3`, так как первое и второе числа Фибоначчи заранее записаны в переменные `a=1`, `b=1`.
|
Loading…
Add table
Add a link
Reference in a new issue