តើអ្នកធ្លាប់ត្រូវបានគេចាប់បានក្នុងវដ្ដហាក់ដូចជាមិនចេះចប់ទេ ដែលបញ្ហាបន្តបែកជាបំណែកតូចៗ?
បើដូច្នេះមែន អ្នកប្រហែលជាបានមកលើពិភពនៃការហៅឡើងវិញដ៏គួរឱ្យទាក់ទាញ។ ខណៈពេលដែលវាហាក់ដូចជាពិបាកយល់ សូមកុំបារម្ភ! នៅក្នុងការប្រកាសនេះ យើងនឹងបន្តដំណើរដ៏គួរឱ្យចាប់អារម្មណ៍មួយ ដើម្បីស្វែងយល់អំពីប្រភេទនៃការបង្កើតឡើងវិញ។
ដូច្នេះសូមចុចឡើងនៅពេលដែលយើងស្វែងរកវិធីសាស្រ្ដជាច្រើន។ រៀបចំដើម្បីចូលទៅក្នុងអាណាចក្រគួរឱ្យចាប់អារម្មណ៍នៃការហៅឡើងវិញហើយសង្កេតមើលសមត្ថភាពគួរឱ្យកត់សម្គាល់របស់វាក្នុងការដោះស្រាយបញ្ហាស្មុគស្មាញ។
តើអ្វីទៅជាការកើតឡើងវិញ?
នៅក្នុងពាក្យជាមូលដ្ឋាន ការហៅឡើងវិញគឺជាបច្ចេកទេសសរសេរកម្មវិធីដ៏មានអានុភាពដែលរួមបញ្ចូលមុខងារហៅខ្លួនឯងក្នុងអំឡុងពេលប្រតិបត្តិ។ វាដូចជាការសម្លឹងមើលទៅក្នុងកញ្ចក់មួយ ហើយឃើញរូបភាពនៅខាងក្នុងរូបភាព ដែលបណ្តាលឱ្យមានវដ្តនៃសេចក្តីយោងខ្លួនឯង។
យើងអាចដោះស្រាយបញ្ហាធំៗដោយប្រើការហៅឡើងវិញដោយបែងចែកវាទៅជាបញ្ហាតូចៗដែលអាចគ្រប់គ្រងបាន។
វាស្រដៀងនឹងការដាក់រូបផ្គុំគ្នាដែលដុំមួយភ្ជាប់ទៅផ្នែកផ្សេងទៀតដើម្បីបង្កើតរូបភាពពេញលេញ។ Recursion អនុញ្ញាតឱ្យយើងដោះស្រាយបញ្ហាប្រកបដោយភាពឆើតឆាយ និងប្រកបដោយប្រសិទ្ធភាព ដោយការធ្វើឡើងវិញនូវការណែនាំដូចគ្នាជាមួយនឹងការបញ្ចូលផ្សេងៗ។
1- ការកើតឡើងវិញដោយផ្ទាល់
ការហៅឡើងវិញដោយផ្ទាល់គឺជាប្រភេទមូលដ្ឋានបំផុតនៃការធ្វើឡើងវិញ ដែលមុខងារហៅខ្លួនឯងដោយផ្ទាល់។ វារួមបញ្ចូលការបែងចែកបញ្ហាទៅជាបញ្ហាតូចៗរហូតដល់ករណីមូលដ្ឋានត្រូវបានសម្រេច ដែលនាំទៅដល់ការបញ្ចប់។
មុខងារ recursive ហៅខ្លួនវាជាមួយធាតុបញ្ចូលផ្សេងៗ ដែលអនុញ្ញាតឱ្យការប្រតិបត្តិនៃការណែនាំដូចគ្នាត្រូវធ្វើម្តងទៀត។ ការអំពាវនាវនីមួយៗបង្កើតឡើងនៅលើចំណុចមុនជាបណ្ដើរៗជិតករណីមូលដ្ឋានដែលបណ្ដាលឱ្យការហៅឡើងវិញត្រូវបញ្ចប់។
សូមពិនិត្យមើលឧទាហរណ៍នេះ។
def countdown(n):
if n <= 0:
return
print(n)
countdown(n - 1)
countdown(5)
លទ្ធផល:
5
4
3
2
1
2- ការកើតឡើងវិញដោយប្រយោល។
ការហៅឡើងវិញដោយប្រយោល បន្ថែមភាពទាក់ទាញដ៏គួរឱ្យចាប់អារម្មណ៍មួយទៅកាន់ផ្លូវដែលកើតឡើងវិញ។ ផ្ទុយទៅនឹងការហៅឡើងវិញដោយផ្ទាល់ ដែលពាក់ព័ន្ធនឹងមុខងារហៅខ្លួនឯងយ៉ាងច្បាស់ ការហៅឡើងវិញដោយប្រយោលរួមមានខ្សែសង្វាក់នៃការហៅមុខងារ។
មុខងារមួយហៅមុខងារមួយទៀត ដែលអាចហៅមុខងារដើម ឬមុខងារផ្សេងទៀតដែលចុងក្រោយត្រឡប់ទៅដើមវិញ។ ការហៅចូលមុខងារបណ្តាញដែលទាក់ទងគ្នានេះបង្កើតឱ្យមានការរាំគួរឱ្យចាប់អារម្មណ៍ ដែលមុខងារជាច្រើនសហការគ្នាដើម្បីដោះស្រាយបញ្ហា។
ឧទាហរណ៍:
def function_A(n):
if n > 0:
print("A:", n)
function_B(n - 1)
def function_B(n):
if n > 0:
print("B:", n)
function_A(n - 1)
function_A(3)
លទ្ធផល:
A: 3
B: 2
A: 1
3- លីនេអ៊ែរ ដំណើរឡើងវិញ
ពិចារណាពីដំណើរចុះមកលើផ្លូវត្រង់មួយជំហានម្តងៗ រហូតដល់អ្នកទៅដល់គោលដៅរបស់អ្នក។ បច្ចេកទេសបន្តបន្ទាប់គ្នានេះ ត្រូវបានបញ្ចូលដោយការហៅឡើងវិញតាមលីនេអ៊ែរ ដែលក្នុងនោះមុខងារមួយដំណើរការការហៅដដែលៗនៅក្នុងមុខងារនីមួយៗ។
ជាមួយនឹងការហៅចេញម្តងទៀត ដំណើរការហៅដដែលៗផ្លាស់ទីទៅជិតករណីមូលដ្ឋានដោយបន្ថយទំហំបញ្ហា។ វាដំណើរការក្នុងលក្ខណៈច្បាស់លាស់ និងលីនេអ៊ែរ ដោយដោះស្រាយបញ្ហារងម្តងមួយៗ រហូតទាល់តែបានចម្លើយចុងក្រោយ។
ឧទាហរណ៍:
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
result = factorial(5)
print(result)
លទ្ធផល:
120
៤-ការដុះឡើងវិញនៃដើមឈើ
នៅពេលដែលមុខងារមួយសាខាចូលទៅក្នុងការហៅឡើងវិញជាច្រើនដង យើងចូលទៅក្នុងពិភពនៃការបង្កើតឡើងវិញនូវមែកធាង។ មុខងារមួយនៅក្នុងការហៅឡើងវិញនៃមែកធាងបង្កើតការហៅឡើងវិញជាច្រើន ដែលនីមួយៗអាចដោះស្រាយបញ្ហារងដាច់ដោយឡែកមួយ ដូចជាមែកធាងរបស់ដើមឈើដែរ។
រចនាសម្ព័ន្ធសាខានេះអនុញ្ញាតឱ្យមានការស៊ើបអង្កេតក្នុងពេលដំណាលគ្នានៃផ្លូវជាច្រើន ដោយមានប្រសិទ្ធភាពបំបែកបញ្ហាស្មុគស្មាញទៅជាផ្នែកតូចៗដែលទាក់ទងគ្នាទៅវិញទៅមក។
ឧទាហរណ៍:
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
result = fibonacci(6)
print(result)
លទ្ធផល:
8
5- សន្ទរកថា
Nested recursion បន្ថែមកម្រិតដ៏គួរឱ្យរំភើបនៃភាពស្មុគស្មាញដល់សកលលោកដែលកើតឡើងវិញ។ នៅក្នុងទម្រង់នៃការហៅឡើងវិញនេះ មុខងារមួយរួមបញ្ចូលការហៅឡើងវិញជាអាគុយម៉ង់មួយនៅក្នុងការហៅឡើងវិញមួយផ្សេងទៀត។
ការហៅឡើងវិញខាងក្នុងធ្វើសកម្មភាពលើតម្លៃដែលពឹងផ្អែកលើការហៅឡើងវិញខាងក្រៅ។ ភាពស្មុគ្រស្មាញកើនឡើងជាមួយនឹងការហៅចូលគ្នាដោយភ្ជាប់គ្នា ដែលឈានដល់គំរូដ៏គួរឱ្យចាប់អារម្មណ៍នៃការហៅទូរស័ព្ទឡើងវិញដែលជាប់គាំង។
ឧទាហរណ៍:
def nested_recursion(n):
if n > 100:
return n - 10
return nested_recursion(nested_recursion(n + 11))
result = nested_recursion(95)
print(result)
លទ្ធផល:
91
៦- កន្ទុយថ្លែន
Tail recursion គឺជាបច្ចេកទេសបង្កើនប្រសិទ្ធភាពសម្រាប់ algorithms recursive ដែលអាចធ្វើអោយដំណើរការរបស់ពួកគេ។ ការហៅឡើងវិញលេចឡើងជាសកម្មភាពចុងក្រោយនៃមុខងារជាមួយនឹងការហៅឡើងវិញដោយកន្ទុយ។
ដោយសារតែមិនមានប្រតិបត្តិការលេចធ្លោបន្ទាប់ពីការហៅឡើងវិញ អ្នកចងក្រង ឬអ្នកបកប្រែអាចសម្រួលការហៅឡើងវិញដោយជំនួសវាដោយការលោតសាមញ្ញ។
វិធីសាស្រ្តបង្កើនប្រសិទ្ធភាពនេះ ដែលគេស្គាល់ថាជាការបង្កើនប្រសិទ្ធភាពការហៅតាមកន្ទុយ កាត់បន្ថយតម្រូវការសម្រាប់ការហៅឡើងវិញនីមួយៗដើម្បីរក្សាស៊ុមជង់ ដែលបណ្តាលឱ្យមានល្បឿនប្រសើរឡើង និងការប្រើប្រាស់អង្គចងចាំទាប។
ឧទាហរណ៍:
def tail_factorial(n, result=1):
if n == 0:
return result
return tail_factorial(n - 1, result * n)
result = tail_factorial(5)
print(result)
ចេញ៖
120
៧-ការមិនកន្ទុយ
ផ្ទុយទៅនឹងការហៅឡើងវិញដោយកន្ទុយ ការហៅឡើងវិញដោយមិនមានកន្ទុយជាប់ពាក់ព័ន្ធនឹងសកម្មភាពបន្ថែមដែលបានធ្វើបន្ទាប់ពីការហៅហៅឡើងវិញក្នុងមុខងារមួយ។ មុនពេលមានសកម្មភាពបន្ថែមទៀត អាចត្រូវបានអនុវត្ត ការហៅសារឡើងវិញនីមួយៗត្រូវតែបំពេញ ហើយត្រលប់មកវិញ។
ជាលទ្ធផល រហូតទាល់តែករណីមូលដ្ឋានត្រូវបានឈានដល់ ហើយការហៅឡើងវិញត្រូវបានបញ្ចប់ ប្រតិបត្តិការដ៏លេចធ្លោមួយត្រូវបានរក្សាទុក។ ការហៅឡើងវិញដែលមិនមែនជាកន្ទុយជាញឹកញាប់ប្រើប្រាស់អង្គចងចាំច្រើនជាង ហើយមានប្រសិទ្ធភាពតិចជាងការហៅឡើងវិញដោយកន្ទុយ ប៉ុន្តែវានៅតែជាឧបករណ៍ដ៏មានប្រយោជន៍សម្រាប់ដោះស្រាយបញ្ហាផ្សេងៗ។
ឧទាហរណ៍:
def non_tail_sum(n):
if n == 0:
return 0
return n + non_tail_sum(n - 1)
result = non_tail_sum(5)
print(result)
លទ្ធផល:
15
រុំឡើង
Recursion គឺជាគំនិតដ៏គួរឱ្យចាប់អារម្មណ៍មួយក្នុងការសរសេរកម្មវិធី។ វាអនុញ្ញាតឱ្យយើងដោះស្រាយបញ្ហាស្មុគ្រស្មាញក្នុងលក្ខណៈនិយាយឡើងវិញ និងយោងដោយខ្លួនឯង។
វាផ្តល់នូវវិធីសាស្រ្តផ្សេងគ្នានៃការគិត និងដោះស្រាយបញ្ហា ដោយបំបែកវាទៅជាផ្នែកតូចៗដែលអាចគ្រប់គ្រងបានច្រើនជាង។ ទោះជាយ៉ាងណាក៏ដោយ នៅពេលធ្វើការជាមួយការហៅឡើងវិញ វាមានសារៈសំខាន់ណាស់ក្នុងការប្រើការយកចិត្តទុកដាក់លើចំណុចមួយចំនួន។
អ្នកគួរតែកំណត់ករណីមូលដ្ឋានសមស្រប ដែលអនុញ្ញាតឱ្យការផ្សាយឡើងវិញបញ្ចប់។ ប្រសិនបើពួកគេមិនមានវត្តមានទេ មុខងារអាចបន្តហៅខ្លួនឯងជារៀងរហូត។
ទីពីរ ដោយផ្អែកលើសេណារីយ៉ូនៅនឹងដៃ ការជ្រើសរើសប្រភេទដែលសមស្របអាចនាំទៅរកដំណោះស្រាយកាន់តែមានប្រសិទ្ធភាព និងឆើតឆាយ។ ព្យាយាមស្វែងរកអ្វីដែលមានប្រសិទ្ធភាពបំផុតសម្រាប់បញ្ហានៅក្នុងដៃ។ នៅពេលធ្វើការជាមួយជម្រៅនៃការហៅឡើងវិញដ៏ធំ សូមប្រយ័ត្នចំពោះគ្រោះថ្នាក់ដែលអាចកើតមាន ដូចជាការហូរលើសជង់។
សូមផ្ដល់យោបល់