logo

CTDL 2005 chuong 6

Đệ quy
Chöông 6 – Ñeä quy Chöông 6 – ÑEÄ QUY Chöông naøy trình baøy veà ñeä quy (recursion) – moät phöông phaùp maø trong ñoù ñeå giaûi moät baøi toaùn, ngöôøi ta giaûi caùc tröôøng hôïp nhoû hôn cuûa noù. Chuùng ta caàn tìm hieåu moät vaøi öùng duïng vaø chöông trình maãu ñeå thaáy ñöôïc moät soá trong raát nhieàu daïng baøi toaùn maø vieäc söû duïng ñeä quy ñeå giaûi raát coù lôïi. Moät soá ví duï ñôn giaûn, moät soá khaùc thöïc söï phöùc taïp. Chuùng ta cuõng seõ phaân tích xem ñeä quy thöôøng ñöôïc hieän thöïc trong maùy tính nhö theá naøo, khi naøo neân duøng ñeä quy vaø khi naøo neân traùnh. 6.1. Giôùi thieäu veà ñeä quy 6.1.1. Cô caáu ngaên xeáp cho caùc laàn goïi haøm Khi moät haøm goïi moät haøm khaùc, thì taát caû caùc traïng thaùi maø haøm goïi ñang coù caàn ñöôïc khoâi phuïc laïi sau khi haøm ñöôïc goïi keát thuùc, ñeå haøm naøy tieáp tuïc thöïc hieän coâng vieäc dôû dang cuûa mình. Traïng thaùi ñoù goàm coù: ñieåm quay veà (doøng leänh keá sau leänh goïi haøm); caùc trò trong caùc thanh ghi, vì caùc thanh ghi trong boä xöû lyù seõ ñöôïc haøm ñöôïc goïi söû duïng ñeán; caùc trò trong caùc bieán cuïc boä vaø caùc tham trò cuûa noù. Nhö vaäy moãi haøm caàn coù moät vuøng nhôù daønh rieâng cho noù. Vuøng nhôù naøy phaûi ñöôïc toàn taïi trong suoát thôøi gian keå töø khi haøm thöïc hieän cho ñeán khi noù keát thuùc coâng vieäc. Hình 6.1- Cô caáu ngaên xeáp cho caùc laàn goïi haøm Giaû söû chuùng ta coù ba haøm A, B, C, maø A goïi B, B goïi C. B seõ khoâng keát thuùc tröôùc khi C keát thuùc. Töông töï, A khôûi söï coâng vieäc ñaàu tieân nhöng laïi keát thuùc cuoái cuøng. Söï dieãn tieán cuûa caùc hoaït ñoäng cuûa caùc haøm xaûy ra theo tính chaát vaøo sau ra tröôùc (Last In First Out –LIFO). Neáu xeùt ñeán nhieäm vuï cuûa maùy tính trong vieäc toå chöùc caùc vuøng nhôù taïm daønh cho caùc haøm naøy söû duïng, chuùng ta thaáy raèng caùc vuøng nhôù naøy cuõng phaûi naèm trong moät danh saùch coù cuøng tính chaát treân, coù nghóa laø ngaên xeáp. Vì theá, ngaên xeáp ñoùng moät vai troø chuû choát lieân quan ñeán caùc haøm trong heä thoáng maùy tính. Trong hình 6.1, M bieåu dieãn chöông trình chính, A, B, C laø caùc haøm treân. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 91 Chöông 6 – Ñeä quy Hình 6.1 bieåu dieãn moät daõy caùc vuøng nhôù taïm cho caùc haøm, moãi coät laø hình aûnh cuûa ngaên xeáp taïi moät thôøi ñieåm, caùc thay ñoåi cuûa ngaên xeáp coù theå ñöôïc nhìn thaáy baèng caùch ñoïc töø traùi sang phaûi. Hình aûnh naøy cuõng cho chuùng ta thaáy raèng khoâng coù söï khaùc nhau trong caùch ñöa moät vuøng nhôù taïm vaøo ngaên xeáp giöõa hai tröôøng hôïp: moät haøm goïi moät haøm khaùc vaø moät haøm goïi chính noù. Ñeä quy laø teân goïi tröôøng hôïp moät haøm goïi chính noù, hay tröôøng hôïp caùc haøm laàn löôït goïi nhau maø trong ñoù coù moät haøm goïi trôû laïi haøm ñaàu tieân. Theo caùch nhìn cuûa cô caáu ngaên xeáp, söï goïi haøm ñeä quy khoâng coù gì khaùc vôùi söï goïi haøm khoâng ñeä quy. 6.1.2. Caây bieåu dieãn caùc laàn goïi haøm Sô ñoà caây (tree diagram) coù theå laøm roõ hôn moái lieân quan giöõa ngaên xeáp vaø vieäc goïi haøm. Sô ñoà caây hình 6.2 töông ñöông vôùi cô caáu ngaên xeáp ôû hình 6.1. Hình 6.2- Caây bieåu dieãn caùc laàn goïi haøm. Chuùng ta baét ñaàu töø goác cuûa caây, töông öùng vôùi chöông trình chính. (Caùc thuaät ngöõ duøng cho caùc thaønh phaàn cuûa caây coù theå tham khaûo trong chöông 9) Moãi voøng troøn goïi laø nuùt cuûa caây, töông öùng vôùi moät laàn goïi haøm. Caùc nuùt ngay döôùi goác caây bieåu dieãn caùc haøm ñöôïc goïi tröïc tieáp töø chöông trình chính. Moãi haøm trong soá treân coù theå goïi haøm khaùc, caùc haøm naøy laïi ñöôïc bieåu dieãn bôûi caùc nuùt ôû saâu hôn. Baèng caùch naøy caây seõ lôùn leân nhö hình 6.2 vaø chuùng ta goïi caây naøy laø caây bieåu dieãn caùc laàn goïi haøm. Ñeå theo veát caùc laàn goïi haøm, chuùng ta baét ñaàu töø goác cuûa caây vaø di chuyeån qua heát caây theo muõi teân trong hình 6.2. Caùch ñi naøy ñöôïc goïi laø pheùp duyeät caây (traversal). Khi ñi xuoáng vaø gaëp moät nuùt, ñoù laø luùc goïi haøm. Sau khi duyeät qua heát phaàn caây beân döôùi, chuùng ta gaëp trôû laïi nuùt naøy, ñoù laø luùc keát thuùc haøm ñöôïc goïi. Caùc nuùt laù bieåu dieãn caùc haøm khoâng goïi moät haøm naøo khaùc. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 92 Chöông 6 – Ñeä quy Chuùng ta ñaëc bieät chuù yù ñeán ñeä quy, do ñoù thoâng thöôøng chuùng ta chæ veõ moät phaàn cuûa caây bieåu dieãn söï goïi ñeä quy, vaø chuùng ta goïi laø caây ñeä quy (recursion tree). Trong sô ñoà caây chuùng ta cuõng löu yù moät ñieàu laø khoâng coù söï khaùc nhau giöõa caùch goïi ñeä quy vôùi caùch goïi haøm khaùc. Söï ñeä quy ñôn giaûn chæ laø söï xuaát hieän cuûa caùc nuùt khaùc nhau trong caây coù quan heä nuùt tröôùc – nuùt sau vôùi nhau maø coù cuøng teân. Ñieåm thöù hai caàn löu yù raèng, chính vì caây bieåu dieãn caùc laàn goïi haøm, neân trong chöông trình, neáu moät leänh goïi haøm chæ xuaát hieän moät laàn nhöng laïi naèm trong voøng laëp, thì nuùt bieåu dieãn haøm seõ xuaát hieän nhieàu laàn trong caây, moãi laàn töông öùng moät laàn goïi haøm. Töông töï, neáu leänh goïi haøm naèm trong phaàn reõ nhaùnh cuûa moät ñieàu kieän maø ñieàu kieän naøy khoâng xaûy ra thì nuùt bieåu dieãn haøm seõ khoâng xuaát hieän trong caây. Cô caáu ngaên xeáp ôû hình 6.1 cho thaáy nhu caàu veà vuøng nhôù cuûa ñeä quy. Neáu moät haøm goïi ñeä quy chính noù vaøi laàn thì baûn sao cuûa caùc bieán khai baùo trong haøm ñöôïc taïo ra cho moãi laàn goïi ñeä quy. Trong caùch hieän thöïc thoâng thöôøng cuûa ñeä quy, chuùng ñöôïc giöõ trong ngaên xeáp. Chuù yù raèng toång dung löôïng vuøng nhôù caàn cho ngaên xeáp naøy tæ leä vôùi chieàu cao cuûa caây ñeä quy chöù khoâng phuï thuoäc vaøo toång soá nuùt trong caây. Ñieàu naøy coù nghóa raèng, toång dung löôïng vuøng nhôù caàn thieát ñeå hieän thöïc moät haøm ñeä quy phuï thuoäc vaøo ñoä saâu cuûa ñeä quy, khoâng phuï thuoäc vaøo soá laàn maø haøm ñöôïc goïi. Hai hình aûnh treân cho chuùng ta thaáy moái lieân quan maät thieát giöõa moät bieåu dieãn caây vaø ngaên xeáp: Trong quaù trình duyeät qua baát kyø moät caây naøo, caùc nuùt ñöôïc theâm vaøo hay laáy ñi ñuùng theo kieåu cuûa ngaên xeáp. Traùi laïi, cho tröôùc moät ngaên xeáp, coù theå veõ moät caây ñeå moâ taû quaù trình thay ñoåi cuûa ngaên xeáp. Chuùng ta haõy tìm hieåu moät vaøi ví duï ñôn giaûn veà ñeä quy. Sau ñoù chuùng ta seõ xem xeùt ñeä quy thöôøng ñöôïc hieän thöïc trong maùy tính nhö theá naøo. 6.1.3. Giai thöøa: Moät ñònh nghóa ñeä quy Trong toaùn hoïc. giai thöøa cuûa moät soá nguyeân thöôøng ñöôïc ñònh nghóa bôûi coâng thöùc: n! = n x (n-1) x ... x 1. Hoaëc ñònh nghóa sau: 1 neáu n=0 n! = n x (n-1)! neáu n>0. Giaû söû chuùng ta caàn tính 4!. Theo ñònh nghóa chuùng ta coù: Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 93 Chöông 6 – Ñeä quy 4! = 4 x 3! = 4 x (3 x 2!) = 4 x (3 x (2 x 1!)) = 4 x (3 x (2 x (1 x 0!))) = 4 x (3 x (2 x (1 x 1))) = 4 x (3 x (2 x 1)) = 4 x (3 x 2) =4x6 = 24 Vieäc tính toaùn treân minh hoïa baûn chaát cuûa caùch maø ñeä quy thöïc hieän. Ñeå coù ñöôïc caâu traû lôøi cho moät baøi toaùn lôùn, phöông phaùp chung laø giaûm baøi toaùn lôùn thaønh moät hoaëc nhieàu baøi toaùn con coù baûn chaát töông töï maø kích thöôùc nhoû hôn. Sau ñoù cuõng chính phöông phaùp chung naøy laïi ñöôïc söû duïng cho nhöõng baøi toaùn con, cöù nhö theá ñeä quy seõ tieáp tuïc cho ñeán khi kích thöôùc cuûa baøi toaùn con ñaõ giaûm ñeán moät kích thöôùc nhoû nhaát naøo ñoù cuûa moät vaøi tröôøng hôïp cô baûn, maø lôøi giaûi cuûa chuùng coù theå coù ñöôïc moät caùch tröïc tieáp khoâng caàn ñeán ñeä quy nöõa. Noùi caùch khaùc: Moïi quaù trình ñeä quy goàm coù hai phaàn: Moät vaøi tröôøng hôïp cô baûn nhoû nhaát coù theå ñöôïc giaûi quyeát maø khoâng caàn ñeä • quy. Moät phöông phaùp chung coù theå giaûm moät tröôøng hôïp thaønh moät hoaëc nhieàu • tröôøng hôïp nhoû hôn, vaø nhôø ñoù vieäc giaûm nhoû vaán ñeà coù theå tieán trieån cho ñeán keát quaû cuoái cuøng laø caùc tröôøng hôïp cô baûn. C++, cuõng nhö caùc ngoân ngöõ maùy tính hieän ñaïi khaùc, cho pheùp ñeä quy deã daøng. Vieäc tính giai thöøa trong C++ trôû thaønh moät haøm sau ñaây. int factorial(int n) /* pre: n laø moät soá khoâng aâm. post: traû veà trò cuûa n giai thöøa. */ { if (n == 0) return 1; else return n * factorial(n - 1); } Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 94 Chöông 6 – Ñeä quy Nhö chuùng ta thaáy, ñònh nghóa ñeä quy vaø lôøi giaûi ñeä quy cuûa moät baøi toaùn ñeàu coù theå raát ngaén goïn vaø ñeïp ñeõ. Tuy nhieân vieäc tính toaùn chi tieát coù theå ñoøi hoûi phaûi giöõ laïi raát nhieàu pheùp tính töøng phaàn tröôùc khi coù ñöôïc keát quaû ñaày ñuû. Maùy tính coù theå deã daøng nhôù caùc tính toaùn töøng phaàn baèng moät ngaên xeáp. Con ngöôøi thì khoù laøm ñöôïc nhö vaäy, con ngöôøi khoù coù theå nhôù moät daõy daøi caùc keát quaû tính toaùn töøng phaàn ñeå roài sau ñoù quay laïi hoaøn taát chuùng. Do ñoù, khi söû duïng ñeä quy, caùch chuùng ta suy nghó coù khaùc vôùi caùc caùch laäp trình khaùc. Chuùng ta phaûi xem xeùt vaán ñeà baèng moät caùch nhìn toång theå vaø daønh nhöõng vieäc tính toaùn chi tieát laïi cho maùy tính. Chuùng ta phaûi ñaëc taû trong giaûi thuaät cuûa chuùng ta moät caùch chính xaùc caùc böôùc toång quaùt cuûa vieäc giaûm moät baøi toaùn lôùn thaønh nhieàu tröôøng hôïp nhoû hôn; chuùng ta phaûi xaùc ñònh ñieàu kieän döøng (caùc tröôøng hôïp nhoû nhaát) vaø caùch giaûi cuûa chuùng. Ngoaïi tröø moät soá ít ví duï nhoû vaø ñôn giaûn, chuùng ta khoâng neân coá gaéng hieåu giaûi thuaät ñeä quy baèng caùch bieán ñoåi töø baøi toaùn ban ñaàu cho ñeán taän böôùc keát thuùc, hoaëc laàn theo veát cuûa caùc coâng vieäc maø maùy tính seõ laøm. Laøm nhö theá, chuùng ta seõ nhanh choùng laãn loän bôûi caùc coâng vieäc bò trì hoaõn laïi vaø chuùng ta seõ bò maát phöông höôùng. 6.1.4. Chia ñeå trò: Baøi toaùn Thaùp Haø Noäi 6.1.4.1. Baøi toaùn Vaøo theá kyû thöù 19 ôû chaâu AÂu xuaát hieän moät troø chôi ñöôïc goïi laø Thaùp Haø Noäi. Ngöôøi ta keå raèng troø chôi naøy bieåu dieãn moät nhieäm vuï ôû moät ngoâi ñeàn cuûa AÁn Ñoä giaùo. Vaøo caùi ngaøy maø theá giôùi môùi ñöôïc taïo neân, caùc vò linh muïc ñöôïc giao cho 3 caùi thaùp baèng kim cöông, taïi thaùp thöù nhaát coù ñeå 64 caùi ñóa baèng vaøng. Caùc linh muïc naøy phaûi di chuyeån caùc ñóa töø thaùp thöù nhaát sang thaùp thöù ba sao cho moãi laàn chæ di chuyeån 1 ñóa vaø khoâng coù ñóa lôùn naèm treân ñóa nhoû. Ngöôøi ta baûo raèng khi coâng vieäc hoaøn taát thì ñeán ngaøy taän theá. Hình 6.3- Baøi toaùn thaùp Haø noäi Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 95 Chöông 6 – Ñeä quy Nhieäm vuï cuûa chuùng ta laø vieát moät chöông trình in ra caùc böôùc di chuyeån caùc ñóa giuùp cho caùc nhaø linh muïc, chuùng ta goïi doøng leänh sau move(64, 1, 3, 2) coù nghóa laø: chuyeån 64 ñóa töø thaùp thöù nhaát sang thaùp thöù ba, söû duïng thaùp thöù hai laøm nôi ñeå taïm. 6.1.4.2. Lôøi giaûi YÙ töôûng ñeå ñeán vôùi lôøi giaûi ôû ñaây laø, söï taäp trung chuù yù cuûa chuùng ta khoâng phaûi laø vaøo böôùc ñaàu tieân di chuyeån caùi ñóa treân cuøng, maø laø vaøo böôùc khoù nhaát: di chuyeån caùi ñóa döôùi cuøng. Ñóa lôùn nhaát döôùi cuøng naøy seõ phaûi coù vò trí ôû döôùi cuøng taïi thaùp thöù ba theo yeâu caàu baøi toaùn. Khoâng coù caùch naøo khaùc ñeå chaïm ñöôïc ñeán ñóa cuoái cuøng tröôùc khi 63 ñóa naèm treân ñaõ ñöôïc chuyeån ñi. Ñoàng thôøi 63 ñóa naøy phaûi ñöôïc ñaët taïi thaùp thöù hai ñeå thaùp thöù ba troáng. Chuùng ta ñaõ coù ñöôïc moät böôùc nhoû ñeå tieán ñeán lôøi giaûi, ñaây laø moät böôùc raát nhoû vì chuùng ta coøn phaûi tìm caùch di chuyeån 63 ñóa. Tuy nhieân ñaây laïi laø moät böôùc raát quan troïng, vì vieäc di chuyeån 63 ñóa ñaõ coù cuøng baûn chaát vôùi baøi toaùn ban ñaàu, vì khoâng coù lyù do gì ngaên caûn vieäc chuùng ta di chuyeån 63 ñóa naøy theo cuøng moät caùch töông töï. move(63,1,2,3);// Chuyeån 63 ñóa töø thaùp 1 sang thaùp 2 (thaùp 3 duøng laøm nôi ñeå taïm). cout Chöông 6 – Ñeä quy Giaû söû raèng baøi toaùn cuûa chuùng ta seõ döøng sau moät soá böôùc höõu haïn (maëc daàu ñoù coù theå laø ngaøy taän theá!), vaø nhö vaäy phaûi coù caùch naøo ñoù ñeå vieäc ñeä quy döøng laïi. Moät ñieàu kieän döøng hieån nhieân laø khi khoâng coøn ñóa caàn di chuyeån nöõa. Chuùng ta coù theå vieát chöông trình sau: // Caàn söûa haèng soá naøy thaät nhoû ñeå chaïy thöû chöông trình. const int disks = 64; void move(int count, int start, int finish, int temp); /* pre: Khoâng coù. post: Chöông trình moâ phoûng baøi toaùn Thaùp Haø Noäi keát thuùc. */ main() { move(disks, 1, 3, 2); } Haøm ñeä quy nhö sau: void move(int count, int start, int finish, int temp) { if (count > 0) { move(count - 1, start, temp, finish); cout Chöông 6 – Ñeä quy Hình 6.4- Theo veát cuûa chöông trình Thaùp Haø Noäi vôùi soá ñóa laø 2. Doøng leänh thöù nhaát vaø doøng leänh thöù ba goïi ñeä quy. Doøng leänh move(1,1,2,3) baét ñaàu goïi haøm move thöïc hieän trôû laïi doøng leänh ñaàu tieân, nhöng vôùi caùc thoâng soá môùi. Doøng leänh naøy seõ thöïc hieän ñuùng ba leänh sau: Chuyeån 0 ñóa (goïi ñeä quy laàn nöõa, bieåu dieãn bôûi khoái nhoû beân move(0,1,3,2);// / / trong). cout Chöông 6 – Ñeä quy Chuùng ta seõ xem xeùt theâm moät coâng cuï khaùc coù tính hieån thò cao hôn trong vieäc bieåu dieãn söï ñeä quy baèng caùch laàn theo veát cuûa chöông trình vöøa roài. 6.1.4.5. Phaân tích Hình 6.5- Caây ñeä quy cho tröôøng hôïp 3 ñóa Hình 6.5 laø caây ñeä quy cho baøi toaùn Thaùp Haø Noäi vôùi 3 ñóa. Löu yù raèng chöông trình cuûa chuùng ta cho baøi toaùn Thaùp Haø Noäi khoâng chæ sinh ra moät lôøi giaûi ñaày ñuû cho baøi toaùn maø coøn sinh ra moät lôøi giaûi toát nhaát coù theå coù, vaø ñaây cuõng laø lôøi giaûi duy nhaát ñöôïc tìm thaáy tröø khi chuùng ta chaáp nhaän lôøi giaûi vôùi moät daõy daøi leâ theâ caùc böôùc dö thöøa vaø baát lôïi nhö sau: Chuyeån ñóa 1 töø thaùp 1 sang thaùp 2. Chuyeån ñóa 1 töø thaùp 2 sang thaùp 3. Chuyeån ñóa 1 töø thaùp 3 sang thaùp 1. . . . Ñeå chöùng minh tính duy nhaát cuûa moät lôøi giaûi khoâng theå giaûn löôïc hôn ñöôïc nöõa, chuùng ta chuù yù raèng, taïi moãi böôùc, nhieäm vuï caàn laøm ñöôïc toång keát laïi laø caàn di chuyeån moät soá ñóa nhaát ñònh naøo ñoù töø moät thaùp naøy sang moät thaùp khaùc. Khoâng coù caùch naøo khaùc ngoaøi caùch laø tröôùc heát phaûi di chuyeån toaøn boä soá ñóa beân treân, tröø ñóa cuoái cuøng naèm döôùi, sau ñoù coù theå thöïc hieän moät soá böôùc dö thöøa naøo ñoù, tieáp theo laø di chuyeån chính ñóa cuoái cuøng, roài laïi coù theå thöïc hieän moät soá böôùc dö thöøa naøo ñoù, ñeå cuoái cuøng laø di chuyeån toaøn boä soá ñóa cuõ veà laïi treân ñóa döôùi cuøng naøy. Nhö vaäy, neáu loaïi ñi taát caû caùc vieäc laøm dö thöøa thì nhöõng vieäc coøn laïi chính laø coát loõi cuûa giaûi thuaät ñeä quy cuûa chuùng ta. Tieáp theo, chuùng ta seõ tính xem ñeä quy ñöôïc goïi lieân tieáp bao nhieâu laàn tröôùc khi coù söï quay veà. Laàn ñaàu ñeä quy coù count=64, moãi laàn ñeä quy count ñöôïc giaûm ñi 1. Vaäy neáu chuùng ta goïi ñeä quy vôùi count = 0, laàn ñeä quy naøy khoâng thöïc hieän gì, chuùng ta coù toång ñoä saâu cuûa ñeä quy laø 64. Ñieàu naøy coù nghóa raèng, neáu chuùng ta veõ caây ñeä quy cho chöông trình, thì caây seõ coù 64 möùc khoâng keå möùc cuûa Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 99 Chöông 6 – Ñeä quy caùc möùc laù. Ngoaïi tröø caùc nuùt laù, caùc nuùt khaùc ñeàu goïi ñeä quy hai laàn trong moãi nuùt, nhö vaäy toång soá nuùt taïi moãi möùc chính xaùc baèng hai laàn toång soá nuùt ôû möùc cao hôn. Töø caùch suy nghó treân veà caây ñeä quy (ngay caû khi caây quaù lôùn khoâng theå veõ ñöôïc), chuùng ta coù theå deã daøng tính ra soá laàn di chuyeån caàn laøm (moãi laàn di chuyeån moät ñóa) ñeå di chuyeån heát 64 ñóa theo yeâu caàu baøi toaùn. Moãi nuùt trong caây seõ in moät lôøi höôùng daãn töông öùng moät laàn chuyeån moät ñóa, tröø caùc nuùt laù. Toång soá nuùt goác vaø nuùt trung gian laø: 1 +2 +4 +... +263 = 20 +21 +22 +... +263 = 264 -1. neân soá laàn di chuyeån ñóa caàn thöïc hieän taát caû laø 264 –1. Chuùng ta coù theå öôùc chöøng con soá naøy lôùn nhö theá naøo baèng caùch so saùnh vôùi 103 = 1000 ≈ 1024 = 210, ta coù toång soá laàn di chuyeån ñóa baèng 264 =24 x 260 ≈24 x 1018 =1.6 x1019 Moãi naêm coù khoaûng 3.2 x 107 giaây. Giaû söû moãi laàn di chuyeån moät ñóa ñöôïc thöïc hieän maát 1 giaây, thì toaøn boä coâng vieäc cuûa caùc linh muïc seõ phaûi thöïc hieän maát 5 x 1011 naêm. Caùc nhaø thieân vaên hoïc öôùc ñoaùn tuoåi thoï cuûa vuõ truï seõ nhoû hôn 20 tæ naêm, nhö vaäy, theo truyeàn thuyeát cuûa baøi toaùn naøy thì theá giôùi coøn keùo daøi hôn caû vieäc tính toaùn ñoù ñeán 25 laàn! Khoâng coù moät maùy tính naøo coù theå chaïy ñöôïc chöông trình Thaùp Haø Noäi, do khoâng ñuû thôøi gian, nhöng roõ raøng khoâng phaûi laø do vaán ñeà khoâng gian. Khoâng gian ôû ñaây chæ ñoøi hoûi 64 laàn goïi ñeä quy. 6.2. Caùc nguyeân taéc cuûa ñeä quy 6.2.1. Thieát keá giaûi thuaät ñeä quy Ñeä quy laø moät coâng cuï cho pheùp ngöôøi laäp trình taäp trung vaøo böôùc chính yeáu cuûa giaûi thuaät maø khoâng phaûi lo laéng taïi thôøi ñieåm khôûi ñaàu veà caùch keát noái böôùc chính yeáu naøy vôùi caùc böôùc khaùc. Khi caàn giaûi quyeát moät vaán ñeà, böôùc tieáp caän ñaàu tieân neân laøm thöôøng laø xem xeùt moät vaøi ví duï ñôn giaûn, vaø chæ sau khi ñaõ hieåu ñöôïc chuùng moät caùch kyõ löôõng, chuùng ta môùi thöû coá gaéng xaây döïng moät phöông phaùp toång quaùt hôn. Moät vaøi ñieåm quan troïng trong vieäc thieát keá moät giaûi thuaät ñeä quy ñöôïc lieät keâ sau ñaây: Tìm böôùc chính yeáu. Haõy baét ñaàu baèng caâu hoûi “Baøi toaùn naøy coù theå ñöôïc chia nhoû nhö theá naøo?” hoaëc “Böôùc chính yeáu trong giai ñoaïn giöõa seõ ñöôïc thöïc hieän Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 100 Chöông 6 – Ñeä quy nhö theá naøo?”. Neân ñaûm baûo raèng caâu traû lôøi cuûa baïn ñôn giaûn nhöng coù tính toång quaùt. Khoâng neân ñi töø ñieåm khôûi ñaàu hay ñieåm keát thuùc cuûa baøi toaùn lôùn, hoaëc sa vaøo quaù nhieàu tröôøng hôïp ñaëc bieät (do chuùng chæ phuø hôïp vôùi caùc baøi toaùn nhoû). Khi ñaõ coù ñöôïc moät böôùc nhoû vaø ñôn giaûn ñeå höôùng tôùi lôøi giaûi, haõy töï hoûi raèng nhöõng khuùc maéc coøn laïi cuûa baøi toaùn coù theå ñöôïc giaûi quyeát baèng caùch töông töï hay khoâng, ñeå söûa laïi phöông phaùp cuûa baïn cho toång quaùt hôn, neáu caàn thieát. Ngoaïi tröø nhöõng ñònh nghóa toaùn hoïc theå hieän söï ñeä quy quaù roõ raøng, moät ñieàu thuù vò maø chuùng ta seõ laàn löôït gaëp trong nhöõng chöông sau laø, khi nhöõng baøi toaùn caàn ñöôïc giaûi quyeát treân nhöõng caáu truùc döõ lieäu maø ñònh nghóa mang tính chaát ñeä quy nhö danh saùch, chuoãi kyù töï bieåu dieãu bieåu thöùc soá hoïc, caây, hay ñoà thò,… thì giaûi phaùp höôùng tôùi moät giaûi thuaät ñeä quy laø raát deã nhìn thaáy. Tìm ñieàu kieän döøng. Ñieàu kieän döøng chæ ra raèng baøi toaùn hoaëc moät phaàn naøo ñoù cuûa baøi toaùn ñaõ ñöôïc giaûi quyeát. Ñieàu kieän döøng thöôøng laø tröôøng hôïp nhoû, ñaëc bieät, coù theå ñöôïc giaûi quyeát moät caùch deã daøng khoâng caàn ñeä quy. Phaùc thaûo giaûi thuaät. Keát hôïp ñieàu kieän döøng vôùi böôùc chính yeáu cuûa baøi toaùn, söû duïng leänh if ñeå choïn löïa giöõa chuùng. Ñeán ñaây thì chuùng ta coù theå vieát haøm ñeä quy, trong ñoù moâ taû caùch maø böôùc chính yeáu ñöôïc tieán haønh cho ñeán khi gaëp ñöôïc ñieàu kieän döøng. Moãi laàn goïi ñeä quy hoaëc laø phaûi giaûi quyeát moät phaàn cuûa baøi toaùn khi gaëp moät trong caùc ñieàu kieän döøng, hoaëc laø phaûi giaûm kích thöôùc baøi toaùn höôùng daàn ñeán ñieàu kieän döøng. Kieåm tra söï keát thuùc. Keá tieáp, vaø cuõng laø ñieàu toái quan troïng, laø phaûi chaéc chaén vieäc goïi deä quy seõ khoâng bò laëp voâ taän. Baét ñaàu töø moät tröôøng hôïp chung, qua moät soá böôùc höõu haïn, chuùng ta caàn kieåm tra lieäu ñieàu kieän döøng coù khaû naêng xaûy ra ñeå quaù trình ñeä quy keát thuùc hay khoâng. Trong baát kyø moät giaûi thuaät naøo, khi moät laàn goïi haøm khoâng phaûi laøm gì, noù thöôøng quay veà moät caùch eâm thaám. Ñoái vôùi giaûi thuaät ñeä quy, ñieàu naøy raát thöôøng xaûy ra, do vieäc goïi haøm maø khoâng phaûi laøm gì thöôøng laø moät ñieàu kieän döøng. Do ñoù, caàn löu yù raèng vieäc goïi haøm maø khoâng laøm gì thöôøng khoâng phaûi laø moät loãi trong tröôøng hôïp cuûa haøm ñeä quy. Kieåm tra laïi moïi tröôøng hôïp ñaëc bieät Cuoái cuøng chuùng ta cuõng caàn baûo ñaûm raèng giaûi thuaät cuûa chuùng ta luoân ñaùp öùng moïi tröôøng hôïp ñaëc bieät. Veõ caây ñeä quy. Coâng cuï chính ñeå phaân tích caùc giaûi thuaät ñeä quy laø caây ñeä quy. Nhö chuùng ta ñaõ thaáy trong baøi toaùn Thaùp Haø Noäi, chieàu cao cuûa caây ñeä quy lieân quan maät thieát ñeán toång dung löôïng boä nhôù maø chöông trình caàn ñeán, vaø kích thöôùc toång coäng cuûa caây phaûn aùnh soá laàn thöïc hieän böôùc chính yeáu vaø cuõng laø toång thôøi gian chaïy chöông trình. Thoâng thöôøng chuùng ta neân veõ caây ñeä quy cho Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 101 Chöông 6 – Ñeä quy moät hoaëc hai tröôøng hôïp ñôn giaûn cuûa baøi toaùn cuûa chuùng ta vì noù seõ chæ daãn cho chuùng ta nhieàu ñieàu. 6.2.2. Caùch thöïc hieän cuûa ñeä quy Caâu hoûi veà caùch hieän thöïc cuûa moät chöông trình ñeä quy trong maùy tính caàn ñöôïc taùch rôøi khoûi caâu hoûi veà söû duïng ñeä quy ñeå thieát keá giaûi thuaät. Trong giai ñoaïn thieát keá, chuùng ta neân söû duïng moïi phöông phaùp giaûi quyeát vaán ñeà maø chuùng toû ra thích hôïp vôùi baøi toaùn, ñeä quy laø moät trong caùc coâng cuï hieäu quaû vaø linh hoaït naøy. Trong giai ñoaïn hieän thöïc, chuùng ta caàn tìm xem phöông phaùp naøo trong soá caùc phöông phaùp seõ laø toát nhaát so vôùi töøng tình huoáng. Coù ít nhaát hai caùch ñeå hieän thöïc ñeä quy trong heä thoáng maùy tính. Quan ñieåm chính cuûa chuùng ta khi xem xeùt hai caùch hieän thöïc khaùc nhau döôùi ñaây laø, cho duø coù söï haïn cheá veà khoâng gian vaø thôøi gian, chuùng cuõng neân ñöôïc taùch rieâng ra khoûi quaù trình thieát keá giaûi thuaät. Caùc loaïi thieát bò tính toaùn khaùc nhau trong töông lai coù theå daãn ñeán nhöõng khaû naêng vaø nhöõng haïn cheá khaùc nhau. Chuùng ta seõ tìm hieåu hai caùch hieän thöïc ña xöû lyù vaø ñôn xöû lyù cuûa ñeä quy döôùi ñaây. 6.2.2.1. Hieän thöïc ña xöû lyù: söï ñoàng thôøi Coù leõ raèng caùch suy nghó töï nhieân veà quaù trình hieän thöïc cuûa ñeä quy laø caùc haøm khoâng chieám nhöõng phaàn rieâng trong cuøng moät maùy tính, maø chuùng seõ ñöôïc thöïc hieän treân nhöõng maùy khaùc nhau. Baèng caùch naøy, khi moät haøm caàn goïi moät haøm khaùc, noù khôûi ñoäng chieác maùy töông öùng, vaø khi maùy naøy keát thuùc coâng vieäc, noù seõ traû veà chieác maùy ban ñaàu keát quaû tính ñöôïc ñeå chieác maùy ban ñaàu coù theå tieáp tuïc coâng vieäc. Neáu moät haøm goïi ñeä quy chính noù hai laàn, ñôn giaûn noù chæ caàn khôûi ñoäng hai chieác maùy khaùc ñeå thöïc hieän cuõng nhöõng doøng leänh y nhö nhöõng doøng leänh maø noù ñang thöïc hieän. Khi hai maùy naøy hoaøn taát coâng vieäc chuùng traû keát quaû veà cho maùy goïi chuùng. Neáu chuùng caàn goïi ñeä quy, dó nhieân chuùng cuõng khôûi ñoäng nhöõng chieác maùy khaùc nöõa. Thoâng thöôøng boä xöû lyù trung öông laø thaønh phaàn ñaét nhaát trong heä thoáng maùy tính, neân baát kyø moät yù nghó naøo veà moät heä thoáng coù nhieàu hôn moät boä xöû lyù cuõng caàn phaûi xem xeùt ñeán söï laõng phí. Nhöng raát coù theå trong töông lai chuùng ta seõ thaáy nhöõng heä thoáng maùy tính lôùn chöùa haøng traêm, neáu khoâng laø haøng ngaøn, caùc boä vi xöû lyù töông töï trong caùc thaønh phaàn cuûa noù. Khi ñoù thì vieäc thöïc hieän ñeä quy baèng nhieàu boä xöû lyù song song seõ trôû neân bình thöôøng. Vôùi ña xöû lyù, nhöõng ngöôøi laäp trình seõ khoâng coøn xem xeùt caùc giaûi thuaät chæ nhö moät chuoãi tuyeán tính caùc haønh ñoäng, thay vaøo ñoù, caàn phaûi nhaän ra moät soá phaàn cuûa giaûi thuaät coù theå thöïc hieän song song. Caùch xöû lyù naøy coøn ñöôïc goïi laø xöû Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 102 Chöông 6 – Ñeä quy lyù ñoàng thôøi (concurrent). Vieäc nghieân cöùu veà xöû lyù ñoàng thôøi vaø caùc phöông phaùp keát noái giöõa chuùng hieän taïi laø moät ñeà taøi nghieân cöùu trong khoa hoïc maùy tính, moät ñieàu chaéc chaén laø noù seõ caûi tieán caùch maø caùc giaûi thuaät seõ ñöôïc moâ taû vaø hieän thöïc trong nhieàu naêm tôùi. 6.2.2.2. Hieän thöïc ñôn xöû lyù: vaán ñeà vuøng nhôù Ñeå xem xeùt laøm caùch naøo maø ñeä quy coù theå ñöôïc thöïc hieän trong moät heä thoáng chæ coù moät boä xöû lyù, chuùng ta nhôù laïi cô caáu ngaên xeáp cuûa caùc laàn goïi haøm ñaõ ñöôïc giôùi thieäu ôû ñaàu chöông naøy. Moät haøm khi ñöôïc goïi caàn phaûi coù moät vuøng nhôù rieâng ñeå chöùa caùc bieán cuïc boä vaø caùc tham trò cuûa noù, keå caû caùc trò trong caùc thanh ghi vaø ñòa chæ quay veà khi noù chuaån bò goïi moät haøm khaùc. Sau khi haøm keát thuùc, noù seõ khoâng coøn caàn ñeán baát cöù thöù gì trong vuøng nhôù daønh rieâng cho noù nöõa. Thöïc söï laø khoâng coù söï khaùc nhau giöõa vieäc goïi moät haøm ñeä quy vaø vieäc goïi moät haøm khoâng ñeä quy. Khi moät haøm chöa keát thuùc, vuøng nhôù cuûa noù laø baát khaû xaâm phaïm. Moät laàn goïi haøm ñeä quy cuõng laø moät laàn goïi haøm rieâng bieät. Chuùng ta caàn chuù yù raèng hai laàn goïi ñeä quy laø hoaøn toaøn khaùc nhau, ñeå chuùng ta khoâng troän laãn vuøng nhôù cuûa chuùng khi chuùng chöa keát thuùc. Ñoái vôùi nhöõng haøm ñeä quy, nhöõng thoâng tin löu tröõ daønh cho laàn goïi ngoaøi caàn ñöôïc giöõ cho ñeán khi noù keát thuùc, nhö vaäy moät laàn goïi beân trong phaûi söû duïng moät vuøng khaùc laøm vuøng nhôù cuûa rieâng noù. Ñoái vôùi moät haøm khoâng ñeä quy, vuøng nhôù coù theå laø moät vuøng coá ñònh vaø ñöôïc daønh cho laâu daøi, do chuùng ta bieát raèng moät laàn goïi haøm seõ ñöôïc traû veà tröôùc khi haøm coù theå laïi ñöôïc goïi laàn nöõa, vaø sau khi laàn goïi tröôùc ñöôïc traû veà, caùc thoâng tin trong vuøng nhôù cuûa noù khoâng coøn caàn thieát nöõa. Vuøng nhôù laâu daøi ñöôïc daønh saün cho caùc haøm khoâng ñeä quy coù theå gaây laõng phí raát lôùn, do nhöõng khi haøm khoâng ñöôïc yeâu caàu thöïc hieän, vuøng nhôù ñoù khoâng theå ñöôïc söû duïng vaøo muïc ñích khaùc. Ñoù cuõng laø caùch quaûn lyù vuøng nhôù daønh cho caùc haøm cuûa caùc phieân baûn cuõ cuûa caùc ngoân ngöõ nhö FORTRAN vaø COBOL, vaø chính ñieàu naøy cuõng laø lyù do maø caùc ngoân ngöõ naøy khoâng cho pheùp ñeä quy. 6.2.2.3. Nhu caàu veà thôøi gian vaø khoâng gian cuûa moät quaù trình ñeä quy Chuùng ta haõy xem laïi caây bieåu dieãn caùc laàn goïi haøm: trong quaù trình duyeät caây, caùc nuùt ñöôïc theâm vaøo hay laáy ñi ñuùng theo kieåu cuûa ngaên xeáp. Quaù trình naøy ñöôïc minh hoïa trong hình 6.1. Töø hình naøy, chuùng ta coù theå keát luaän ngay raèng toång dung löôïng vuøng nhôù caàn ñeå hieän thöïc ñeä quy tæ leä thuaän vôùi chieàu cao cuûa caây ñeä quy. Nhöõng ngöôøi laäp trình khoâng tìm hieåu kyõ veà ñeä quy thænh thoaûng vaãn nhaàm laãn raèng khoâng gian caàn phaûi coù lieân quan ñeán toång soá nuùt trong caây. Thôøi gian chaïy chöông trình lieân quan ñeán soá laàn goïi haøm, ñoù laø toång soá nuùt trong caây; nhöng dung löôïng vuøng nhôù taïi moät thôøi ñieåm chæ laø toång caùc vuøng nhôù daønh cho caùc nuùt naèm treân ñöôøng ñi töø nuùt töông öùng vôùi haøm ñang thöïc thi ngöôïc veà goác cuûa caây. Khoâng gian caàn Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 103 Chöông 6 – Ñeä quy thieát ñöôïc phaûn aùnh bôûi chieàu cao cuûa caây. Moät caây ñeä quy coù nhieàu nuùt nhöng khoâng cao theå hieän moät quaù trình ñeä quy maø noù thöïc hieän ñöôïc raát nhieàu coâng vieäc treân moät vuøng nhôù khoâng lôùn. 6.2.3. Ñeä quy ñuoâi Chuùng ta haõy xeùt ñeán tröôøng hôïp haønh ñoäng cuoái cuøng trong moät haøm laø vieäc goïi ñeä quy chính noù. Haõy xem xeùt ngaên xeáp daønh cho quaù trình ñeä quy, nhö chuùng ta thaáy, caùc thoâng tin caàn ñeå khoâi phuïc laïi traïng thaùi cho laàn ñeä quy ngoaøi seõ ñöôïc löu laïi ngay tröôùc khi laàn ñeä quy trong ñöôïc goïi. Tuy nhieân khi laàn ñeä quy trong thöïc hieän xong thì laàn ñeä quy ngoaøi cuõng khoâng coøn vieäc gì phaûi laøm nöõa, do vieäc goïi ñeä quy laø haønh ñoäng cuoái cuøng cuûa haøm neân ñaây cuõng laø luùc maø haøm ñeä quy ngoaøi keát thuùc. Vaø nhö vaäy vieäc löu laïi nhöõng thoâng tin duøng ñeå khoâi phuïc traïng thaùi cuõ cuûa laàn ñeä quy ngoaøi trôû neân hoaøn toaøn voâ ích. Moïi vieäc caàn laøm ôû ñaây chæ laø gaùn caùc trò caàn thieát cho caùc bieán vaø quay ngay trôû veà ñaàu haøm, caùc bieán ñöôïc gaùn trò y nhö laø chính haøm ñeä quy beân trong nhaän ñöôïc qua danh saùch thoâng soá vaäy. Chuùng ta toång keát nguyeân taéc naøy nhö sau: Neáu doøng leänh seõ ñöôïc chaïy cuoái cuøng trong moät haøm laø goïi ñeä quy chính noù, thì vieäc goïi ñeä quy naøy coù theå ñöôïc loaïi boû baèng caùch gaùn laïi caùc thoâng soá goïi theo caùc giaù trò nhö laø ñeä quy vaãn ñöôïc goïi, vaø sau ñoù laäp laïi toaøn boä haøm. Hình 6.6 – Ñeä quy ñuoâi Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 104 Chöông 6 – Ñeä quy Quaù trình thay ñoåi naøy ñöôïc minh hoïa trong hình 6.6. Hình 6.6a theå hieän vuøng nhôù ñöôïc söû duïng bôûi chöông trình goïi M vaø moät soá baûn sao cuûa haøm ñeä quy P, moãi haøm moät vuøng nhôù rieâng. Caùc muõi teân xuoáng theå hieän söï goïi haøm. Moãi söï goïi töø P ñeán chính noù cuõng laø haønh ñoäng cuoái trong haøm, vieäc duy trì vuøng nhôù cho haøm trong khi chôø ñôïi söï traû veà töø haøm ñöôïc goïi laø khoâng caàn thieát. Caùch bieán ñoåi nhö treân seõ giaûm kích thöôùc vuøng nhôù ñaùng keå (hình 6.6b). Cuoái cuøng, hình 6.6c bieåu dieãn caùc laàn goïi haøm P nhö moät daïng laëp laïi trong cuøng moät möùc cuûa sô ñoà. Tröôøng hôïp ñaëc bieät chuùng ta vöøa neâu treân laø voâ cuøng quan troïng vì noù cuõng thöôøng xuyeân xaûy ra. Chuùng ta goïi ñoù laø tröôøng hôïp ñeä quy ñuoâi (tail recursion). Chuùng ta neân caån thaän raèng trong ñeä quy ñuoâi, vieäc goïi ñeä quy laø haønh ñoäng cuoái trong haøm, chöù khoâng phaûi laø doøng leänh cuoái ñöôïc vieát trong haøm. Trong chöông trình coù khi chuùng ta thaáy ñeä quy ñuoâi xuaát hieän trong leänh switch hoaëc leänh if trong haøm maø sau ñoù coøn coù theå coù nhieàu doøng leänh khaùc nöõa. Ñoái vôùi phaàn lôùn caùc trình bieân dòch, chæ coù moät söï khaùc nhau nhoû giöõa thôøi gian chaïy trong hai tröôøng hôïp: tröôøng hôïp ñeä quy ñuoâi vaø tröôøng hôïp noù ñaõ ñöôïc thay theá baèng voøng leänh laëp. Tuy nhieân, neáu khoâng gian ñöôïc xem laø quan troïng, thì vieäc loaïi ñeä quy ñuoâi laø raát caàn thieát. Ñeä quy ñuoâi thöôøng ñöôïc thay bôûi voøng laëp while hoaëc do while. Trong giaûi thuaät chia ñeå trò cuûa baøi toaùn Thaùp Haø Noäi, laàn goïi ñeä quy treân khoâng phaûi laø ñeä quy ñuoâi, laàn goïi sau ñoù môùi laø ñeä quy ñuoâi. Haøm sau ñaây ñaõ ñöôïc loaïi ñeä quy ñuoâi: void move(int count, int start, int finish, int temp) move: phieân baûn laëp. /* pre: count laø soá ñóa caàn di chuyeån. post: count ñóa ñaõ ñöôïc chuyeån töø start sang finish duøng temp laøm nôi chöùa taïm. */ { int swap; while (count > 0) { // Thay leänh if trong ñeä quy baèng voøng laëp. move(count - 1, start, temp, finish);// laàn goïi ñeä quy ñaàu khoâng phaûi // ñeä quy ñuoâi. cout Chöông 6 – Ñeä quy Thaät ra chuùng ta coù theå nghó ngay ñeán phöông aùn naøy khi môùi baét ñaàu giaûi baøi toaùn. Nhöng chuùng ta ñaõ xem xeùt noù töø moät caùch nhìn khaùc, baây giôø chuùng ta seõ lyù giaûi laïi caùc doøng leänh treân moät caùch töï nhieân hôn. Chuùng ta seõ thaáy raèng hai thaùp start vaø temp khoâng coù gì khaùc nhau, do chuùng cuøng ñöôïc söû duïng ñeå laøm nôi chöùa taïm trong khi chuùng ta chuyeån daàn caùc ñóa veà thaùp finish. Ñeå chuyeån moät soá ñóa töø start veà finish, chuùng ta chuyeån taát caû ñóa trong soá ñoù, tröø caùi cuoái cuøng, sang thaùp coøn laïi laø temp. Sau ñoù chuyeån ñóa cuoái sang finish. Tieáp tuïc laëp laïi vieäc vöøa roài, chuùng ta laïi caàn chuyeån taát caû caùc ñóa töø temp, tröø caùi cuoái cuøng, sang thaùp coøn laïi laø start, ñeå coù theå chuyeån ñóa cuoái cuøng sang finish. Laàn thöïc hieän thöù hai naøy söû duïng laïi caùc doøng leänh trong chöông trình baèng caùch hoaùn ñoåi start vôùi temp. Cöù nhö theá, sau moãi laàn hoaùn ñoåi start vôùi temp, coâng vieäc ñöôïc laëp laïi y nhö nhau, keát quaû cuûa moãi laàn laëp laø chuùng ta coù ñöôïc theâm moät ñóa môùi treân finish. 6.2.4. Phaân tích moät soá tröôøng hôïp neân vaø khoâng neân duøng ñeä quy 6.2.4.1. Giai thöøa Chuùng ta haõy xem xeùt hai haøm tính giai thöøa sau ñaây. Ñaây laø haøm ñeä quy: int factorial(int n) factorial: phieân baûn ñeä quy. /* pre: n laø moät soá khoâng aâm. post: traû veà trò cuûa n giai thöøa. */ { if (n == 0) return 1; else return n * factorial(n - 1); } Vaø ñaây laø haøm khoâng ñeä quy: int factorial(int n) factorial: phieân baûn khoâng ñeä quy. /* pre: n laø moät soá khoâng aâm. post: traû veà trò cuûa n giai thöøa. */ { int count, product = 1; for (count = 1; count Chöông 6 – Ñeä quy n, n-1, n-2, ..., 2, 1 laø nhöõng thoâng soá ñeå goïi ñeä quy (hình 6.7), vaø theo caùch ñeä quy cuûa mình, noù cuõng phaûi nhaân caùc soá laïi vôùi nhau theo moät thöù töï khoâng khaùc gì so vôùi chöông trình khoâng ñeä quy. Tieán trình thöïc hieän cuûa chöông trình ñeä quy cho n = 5 nhö sau: factorial(5) =5*factorial(4) =5*(4*factorial(3)) =5*(4*(3*factorial(2))) =5*(4*(3*(2*factorial(1)))) =5*(4*(3*(2*(1*factorial(0))))) =5*(4*(3*(2*(1*1)))) =5*(4*(3*(2*1))) =5*(4*(3*2)) =5*(4*6) =5*24 =120 Hình 6.7 – Caây ñeä quy tính giai thöøa Nhö vaäy chöông trình ñeä quy chieám nhieàu vuøng nhôù hôn chöông trình khoâng ñeä quy, ñoàng thôøi noù cuõng chieám nhieàu thôøi gian hôn do chuùng vöøa phaûi caát vaø laáy caùc trò töø ngaên xeáp vöøa phaûi thöïc hieän vieäc tính toaùn. 6.2.4.2. Caùc soá Fibonacci Moät ví duï coøn laõng phí hôn chöông trình tính giai thöøa laø vieäc tính caùc soá Fibonacci. Caùc soá naøy ñöôïc ñònh nghóa nhö sau: Fn = Fn-1 + Fn-2 neáu n ≥2. F0 = 0, F1 = 1, Chöông trình ñeä quy tính caùc soá Fibonacci raát gioáng vôùi ñònh nghóa: int fibonacci(int n) fibonacci: phieân baûn ñeä quy. /* pre: n laø moät soá khoâng aâm. post: traû veà soá Fibonacci thöù n. */ { if (n Chöông 6 – Ñeä quy Thöïc teá, chöông trình naøy troâng raát ñeïp maét, do noù coù daïng chia ñeå trò: keát quaû coù ñöôïc baèng caùch tính toaùn hai tröôøng hôïp nhoû hôn. Tuy nhieân, chuùng ta seõ thaáy raèng ñaây hoaøn toaøn khoâng phaûi laø tröôøng hôïp “chia ñeå trò”, maø laø “chia laøm cho phöùc taïp theâm”. Hình 6.8- Caây ñeä quy tính F7. Ñeå xem xeùt giaûi thuaät naøy, chuùng ta thöû tính F7, minh hoïa trong hình 6.8. Tröôùc heát haøm caàn tính F6 vaø F5. Ñeå coù F6, phaûi coù F5 vaø F4, vaø cöù nhö theá tieáp tuïc. Nhöng sau khi F5 ñöôïc tính ñeå coù ñöôïc F6, thì F5 seõ khoâng ñöôïc giöõ laïi. Nhö vaäy ñeå tính F7 sau ñoù, F5 laïi phaûi ñöôïc tính laïi. Caây ñeä quy ñaõ cho chuùng ta thaáy raát roõ raèng chöông trình ñeä quy phaûi laäp ñi laäp laïi nhieàu pheùp tính moät caùch khoâng caàn thieát.Toång thôøi gian ñeå haøm ñeä quy tính ñöôïc Fn laø moät haøm muõ cuûa n. Cuõng gioáng nhö vieäc tính giai thöøa, chuùng ta coù theå coù ñöôïc moät chöông trình ñôn giaûn baèng caùch giöõ laïi ba bieán, ñoù laø trò cuûa soá Fibonacci môùi nhaát vaø hai soá Fibonacci keá tröôùc: int fibonacci(int n) fibonacci: phieân baûn khoâng ñeä quy. /* pre: n laø moät soá khoâng aâm. post: traû veà soá Fibonacci thöù n. */ { Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 108 Chöông 6 – Ñeä quy // soá Fibonacci hieän taïi Fi int current; int last_value; // Fi-1 int last_but_one; // Fi-2 if (n Chöông 6 – Ñeä quy Trong nhöõng tröôøng hôïp nhö vaäy, toát hôn heát laø thay ngaên xeáp baèng moät caáu truùc döõ lieäu khaùc, moät caáu truùc döõ lieäu maø cho pheùp truy nhaäp vaøo nhieàu vò trí khaùc nhau thay vì chæ ôû ñænh nhö ngaên xeáp. Trong ví duï ñôn giaûn veà caùc soá Fibonacci, chuùng ta chæ caàn theâm hai bieán taïm ñeå chöùa hai trò caàn cho vieäc tính soá môùi. Cuoái cuøng, khaùc vôùi vieäc moät chöông trình ñeä quy töï taïo cho mình moät ngaên xeáp rieâng, baèng caùch taïo moät ngaên xeáp töôøng minh, chuùng ta luoân coù theå chuyeån moïi chöông trình ñeä quy thaønh chöông trình khoâng ñeä quy. Chöông trình khoâng ñeä quy thöôøng phöùc taïp vaø khoù hieåu hôn. Neáu moät chöông trình ñeä quy coù theå chaïy ñöôïc vôùi moät khoâng gian vaø thôøi gian cho pheùp, thì chuùng ta khoâng neân khöû ñeä quy tröø tröôøng hôïp ngoân ngöõ laäp trình maø chuùng ta söû duïng khoâng coù khaû naêng ñeä quy. 6.2.4.4. So saùnh giöõa Fibonacci vaø Thaùp Haø Noäi: kích thöôùc cuûa lôøi giaûi Haøm ñeä quy tính caùc soá Fibonacci vaø haøm ñeä quy giaûi baøi toaùn Thaùp Haø Noäi ñeàu coù daïng chia ñeå trò raát gioáng nhau. Moãi haøm ñeàu goïi ñeä quy chính noù hai laàn cho caùc tröôøng hôïp nhoû hôn. Tuy nhieân, vì sao chöông trình Thaùp Haø Noäi laïi voâ cuøng hieäu quaû trong khi chöông trình tính caùc soá Fibonacci laïi hoaøn toaøn ngöôïc laïi? Caâu traû lôøi lieân quan ñeán kích thöôùc cuûa lôøi giaûi. Ñeå tính moät soá Fibonacci, roõ raøng keát quaû maø chuùng ta caàn chæ coù moãi moät soá, vaø chuùng ta mong muoán vieäc tính toaùn seõ hoaøn taát qua moät soá ít caùc böôùc, nhö laø caùc doøng leänh trong chöông trình khoâng ñeä quy. Trong khi ñoù, chöông trình ñeä quy Fibonacci laïi thöïc hieän quaù nhieàu böôùc. Trong chöông trình Thaùp Haø Noäi, ngöôïc laïi, kích thöôùc cuûa lôøi giaûi laø soá caùc lôøi chæ daãn caàn in ra cho caùc linh muïc vaø laø moät haøm muõ cuûa toång soá ñóa. 6.2.5. Caùc nhaän xeùt Ñeå ñi ñeán keát luaän veà giaûi phaùp löïa choïn cho moät chöông trình ñeä quy hay khoâng ñeä quy, ñieåm baét ñaàu toát nhaát cuõng laø xem xeùt caây ñeä quy. Neáu caây ñeä quy coù daïng ñôn giaûn, chöông trình khoâng ñeä quy seõ toát hôn. Neáu caây chöùa nhieàu coâng vieäc ñöôïc laëp laïi maø caùc caáu truùc döõ lieäu khaùc thích hôïp hôn laø ngaên xeáp, thì ñeä quy cuõng khoâng coøn caàn thieát nöõa. Neáu caây ñeä quy thöïc söï “raäm raïp”, maø trong ñoù soá coâng vieäc laëp laïi khoâng ñaùng keå, thì chöông trình ñeä quy laø giaûi phaùp toát nhaát. Ngaên xeáp ñöôïc söû duïng khi ñeä quy (do chöông trình ñeä quy töï taïo laáy) ñöôïc xem nhö moät danh saùch chöùa caùc coâng vieäc caàn trì hoaõn cuûa chöông trình. Neáu danh saùch naøy coù theå ñöôïc taïo tröôùc, thì chuùng ta neân vieát chöông trình khoâng ñeä quy, ngöôïc laïi, chuùng ta seõ vieát chöông trình ñeä quy. Ñeä quy nhö moät caùch tieáp caän töø treân xuoáng khi caàn giaûi quyeát vaán ñeà, noù chia baøi toaùn thaønh nhöõng baøi toaùn nhoû hôn, hoaëc choïn ra böôùc chuû yeáu vaø trì hoaõn caùc böôùc coøn laïi. Chöông trình khoâng ñeä quy gaàn vôùi caùch tieáp caän töø döôùi leân, noù baét ñaàu töø nhöõng caùi ñaõ bieát vaø töøng böôùc xaây döïng neân lôøi giaûi. Giaùo trình Caáu truùc döõ lieäu vaø Giaûi thuaät 110
DMCA.com Protection Status Copyright by webtailieu.net