§ 7. Паняцце дапаможнага алгарытму
7.6. Рэкурсія
Рэкурсія — у праграмаванні выклік падпраграмы (прама ці ўскосна) з яе ж самой. Колькасць укладзеных выклікаў падпраграмы называюць глыбінёй рэкурсіі. Адрозніваюць прамую (простую, непасрэдную) і ўскосную (складаную, апасродкаваную) рэкурсію. Прамая рэкурсія: пры апісанні функцыі выкарыстоўваецца зварот да яе ж самой, але з іншым наборам параметраў. Ускосная рэкурсія: падпраграма выклікае якую-небудзь іншую падпраграму, у апісанні якой змяшчааецца выклік зыходнай (напрыклад, функцыя A выклікае функцыю B, а функцыя B выклікае функцыю A). Ускосны выклік можа быць арганізаваны і больш складаным чынам, г. зн. у рэкурсію могуць быць уключаны некалькі падпраграм. Рэкурсіўная праграма дазваляе апісаць паўтаральныя дзеянні без відавочных паўтораў частак праграмы і выкарыстання цыклаў. Структура рэкурсіўнай функцыі змяшчае каманду галінавання. Умова ў гэтай камандзе вызначае, калі рэкурсія павінна спыніцца. Па адной з галін гэтай каманды павінен адбывацца хоць бы адзін рэкурсіўны выклік (прамы ці ўскосны) функцыяй самой сябе. Правільна напісаная рэкурсіўная функцыя павінна гарантаваць, што праз канечную колькасць рэкурсіўных выклікаў будзе дасягнута выкананне ўмовы спынення рэкурсіі, у выніку чаго ланцуг паслядоўных рэкурсіўных выклікаў перапыніцца і выканаецца вяртанне. Любая рэкурсіўная функцыя можа быць рэалізавана не рэкурсіўна. Прыклад 7.14. Апісаць алгарытм Эўкліда з дапамогай рэкурсіўнай функцыі. Этапы выканання задання I. Зыходныя даныя: два лікі a, b. II. Вынік: НОД (a, b). III. Алгарытм рашэння задачы. 1. Увод зыходных даных. IV. Апісанне пераменных: a, b, c, d — int. Прыклад 7.15. Напісаць праграму, якая выводзіць раскладанне ліку на простыя множнікі. Этапы выканання задання I. Зыходныя даныя: число n. II. Вынік: простыя множнікі ліку a. III. Алгарытм рашэння задачы. 1. Увод зыходных даных. 3.1. Параметр а — лік, які спрабуем дзяліць, параметр b — лік, на які спрабуем дзяліць. IV. Апісанне пераменных: n — int. З дапамогай рэкурсіі зручна рэалізоўваць рашэнне такіх задач, у якіх сам алгарытм, што рэалізоўваецца, у сутнасці рэкурсіўны. Дастаткова проста апісаць рэкурсіўную функцыю, калі рашэнне задачы можа быць апісана з дапамогай рэкурэнтных суадносін. Прыклад 7.16. Па азначэнні Напісаць праграму, якая знаходзіць an, выкарыстоўваючы апісаны вышэй алгарытм. Этапы выканання задання I. Зыходныя даныя: числа a і n. II. Вынік: значэнне an. III. Алгарытм рашэння задачы. 1. Увод зыходных даных. 2.1. Параметр x — аснова ступені, параметр k — паказчык. 3. Вывад выніку. IV. Апісанне пераменных: a, n — int. |
У некаторых дэкларатыўных або чыста функцыянальных мовах (такіх як Пралог ці Haskell) няма сінтаксічных сродкаў для арганізацыі цыклаў. У іх рэкурсія з’яўляецца адзіным даступным механізмам для арганізацыі паўтаральных вылічэнняў. Пытанне пра пажаданасць выкарыстання рэкурсіўных функцый у праграміраванні неадназначны: з аднаго боку, рэкурсіўная форма можа быць структурна больш простай і нагляднай, асабліва калі сам рэалізуемы алгарытм у сутнасці рэкурсіўны. З іншага боку, звычайна рэкамендуецца пазбягаць рэкурсіўных праграм, якія прыводзяць (ці ў некаторых умовах могуць прыводзіць) да занадта вялікай глыбіні рэкурсіі. Класічным прыкладам бясконцай рэкурсіі з’яўляюцца два пастаўленыя адно насупраць аднаго люстэркі: у іх утвараюцца два калідоры з адлюстраванняў люстэркаў, якія памяншаюцца. Рэкурсія ляжыць у аснове пабудовы фрактальных малюнкаў. Прыклад 7.14. V. Праграма:
VI. Тэсціраванне: Рэкурсіўная функцыя для вылічэння НАД двух лікаў можа быць запісана з выкарыстаннем тэрнарнай (ад лац. ternarius — трайны) умоўнай аперацыі.
Аперацыя, якая структурна запісваецца як o1 : o2 : o3, вяртае свой другі (o2) або трэці (o3) аперанд у залежнасці ад значэння лагічнага зададзенага выразу, зададзенага першым аперандам (o1). Прыклад 7.15. V. Праграма:
VI. Тэсціраванне: VII. Аналіз выніку. Каб зразумець, чаму мы перабіраем простыя множнікі, пачынаючы з меншага, а праграма выводзіць іх у адваротным парадку, распішам парадак выканання каманд у праграме.
СЗахаванне выклікаў рэкурсіўнай функцыі разам са значэннямі параметраў і адрасам звяртання забяспечвае механізм стэка [1] выклікаў. Кожны рэкурсіўны выклік патрабуе некаторай колькасці аператыўнай памяці кампутара, таму пры празмеру вялікай глыбіні рэкурсіі можа наступіць перапаўненне стэка выклікаў. Прыклад 7.16. V. Праграма:
VI. Тэсціраванне: |