рекурсивні факторіали

Приклад 1.8 демонструє ще один спосіб обчислення факториалов. У ньому використовується прийом програмування, званий рекур% сией. Рекурсія має місце, коли метод викликає сам себе, або, дру шими словами, рекурсивно звертається до себе. Рекурсивний алгоритм обчислення факториалов грунтується на тому факті, що n! дорівнює n * (n 1). Такий спосіб обчислення факториалов є класичним ким прикладом рекурсії. В цьому випадку цей прийом не особливо ефек тівен, але у рекурсії є безліч важливих застосувань, і цей при заходів доводить, що її застосування в Java абсолютно законно. У цьому прикладі також замість типу даних int, що є 32 бітовим це лим, використовується тип даних long, є 64 бітовим цілим. Факторіали швидко стають дуже великими, так що додаткового кові ємність типу long робить метод factorial () більш корисним.

Приклад 1.8. Factorial2.java

Дайте відповідь на це клас демонструє рекурсивний спосіб обчислення факториалов. цей

* Метод багаторазово викликає сам себе, грунтуючись на формулі: n! = N * (n 1)! ** /

public class Factorial2

public static long factorial (long x)

if (x <0) throw new IllegalArgumentException("x должен быть>= 0 ");

if (x <= 1) return 1; // Здесь рекурсия прекращается

else return x * factorial (x 1); // Крок рекурсії - виклик самого себе

Приклад 1.9 пред'являє вдосконалений варіант попередніх прикладів, що обчислюють факторіали. Факторіали - це ідеальні кандидати для кешування, оскільки їх обчислення вимагає часу укладання і, що ще важливіше, ви можете вирахувати не так вже й багато факто ріалів в силу обмеженості типу даних long. Тому в цих при заходи, якщо вже факторіал обчислений, його значення зберігається для бу дущего вживання.

Крім демонстрації прийомів кешування в цьому прикладі вводить ся дещо нове. По-перше, в класі Factorial3 визначаються дива етичні поля:

static long [] table = new long [21];

static int last = 0;

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

По-друге, в цьому прикладі можна побачити, як створюються масиви:

static long [] table = new long [21];

Перша половина цього рядка (перед знаком =) оголошує статичне поле table, яке буде масивом значень типу long. Друга полови на цього рядка створює масив з 21 значення типу long за допомогою оператора new.

Нарешті, в цьому прикладі показано, як генеруються винятку:

throw new IllegalArgumentException ( "Переповнення: x занадто великий.");

Винятки - це вид об'єктів Java. Вони, як і масиви, створюються за допомогою ключового слова new. Якщо програма генерує об'єкт виключення за допомогою оператора throw, це означає, що виникла несподівана обставина або помилка. Коли виникає исключе ня, управління в програмі передається найближчій секції catch опе ратора try / catch. Ця секція повинна містити код для обробки ис винятком. Якщо винятку не буде перехоплено, виконання про грами припиняється з повідомленням про помилку.

У прикладі 1.9 виникає виняток, що повідомляє зухвалу процедуру про те, що переданий нею аргумент занадто великий або занадто малий. Аргумент занадто великий, якщо він більше 20, посколь ку ми не можемо обчислювати факторіали, що перевищують 20. Аргумент занадто малий, якщо він менше 0, так як факторіали визначені тільки для невід'ємних цілих чисел. Як перехоплювати і обра бативает виключення, показано в наступних прикладах цієї глави.

класи використовуються в програмі. Після того як, наприклад, клас java.math.BigInteger імпортовано, вам вже не потрібно писати його підлогу ное ім'я; ви можете посилатися на нього просто як на BigInteger. Ви мо жете імпортувати також цілий пакет класів, включивши в файл, на приклад, такий рядок:

Зверніть увагу на те, що класи пакету java.lang автоматично імпортовані, оскільки вони належать поточному пакету, кото рим в нашому випадку є com.davidflanagan.examples.basics.

У прикладі 1.10 застосовується та ж техніка кешування, що і в при мері 1.9. Однак оскільки безліч факториалов, які можуть бути обчислені, тепер не обмежена зверху, для кешування нель зя застосувати масив фіксованого розміру. Замість цього в прикладі використовується java.util.ArrayList - службовий клас, який реалізує структуру даних, подібну масивів і здатну розростатися до будь-якого потрібного розміру. Оскільки ArrayList - це об'єкт, а не мас сив, при роботі з ним доводиться застосовувати методи, такі як size (), add () і get (). Точно так же BigInteger - це об'єкт, а не примітивне значення, тому для множення об'єктів BigInteger не можна примі нять оператор *. Замість цього використовується метод multiply ().

Приклад 1.10. Factorial4.java

// Імпортуємо класи, які маємо намір використовувати в нашій програмі.

// Імпортувавши клас, ми вже не зобов'язані називати його повним ім'ям.

import java.math.BigInteger; // Імпортуємо клас BigInteger з пакета java.math import java.util. *; // Імпортуємо всі класи (включаючи ArrayList)

* У цій версії програми застосовуються цілі числа довільно великого

* Розміру, тому що обчислюються значення не обмежені зверху.

* Для кешування обчислених значень в ній застосовується об'єкт ArrayList

* Замість масивів фіксованого розміру. ArrayList схожий на масив,

* Але може розростатися до будь-якого розміру. Метод factorial () оголошений

* Як «synchronized», тому його можна сміливо використовувати в

* Багатопоточних програмах. При вивченні цього класу познайомтеся

* З java.math.BigInteger і java.util.ArrayList. Працюючи з версіями Java,

* Попередніми Java 1.2, використовуйте Vector замість ArrayList.

public class Factorial4

protected static ArrayList table = new ArrayList (); // Створюємо кеш static

/ ** Метод factorial (), який використовує об'єкти BigInteger, які зберігаються в ArrayList * /

public static synchronized BigInteger factorial (int x)

Схожі статті