آیا تا به حال در یک چرخه به ظاهر پایان ناپذیر گرفتار شده اید که در آن یک مشکل همچنان به قطعات کوچکتر منشعب می شود؟
اگر چنین است، ممکن است به دنیای شگفت انگیز بازگشت رسیده باشید. اگرچه ممکن است درک آن چالش برانگیز به نظر برسد، نگران نباشید! در این پست به سفری جالب می رویم تا با انواع بازگشت ها آشنا شویم.
بنابراین با بررسی چندین رویکرد بازگشتی، دست و پنجه نرم کنید. برای ورود به قلمرو جذاب بازگشت و مشاهده توانایی قابل توجه آن در حل مسائل پیچیده آماده شوید.
Recursions دقیقا چیست؟
به عبارت اولیه، بازگشت یک تکنیک برنامه نویسی قدرتمند است که شامل تابعی است که خود را در حین اجرا فراخوانی می کند. این مانند خیره شدن به آینه و دیدن تصویری در داخل یک تصویر است که در نتیجه یک چرخه خودارجاعی ایجاد می شود.
ما میتوانیم با تقسیم کردن آنها به زیرمشکلات کوچکتر و قابل مدیریتتر، با استفاده از بازگشت، با مسائل بزرگ مقابله کنیم.
این شبیه به کنار هم قرار دادن یک اره منبت کاری اره مویی است که در آن یک قطعه به قسمت های دیگر متصل می شود تا یک تصویر کامل ایجاد شود. بازگشت به ما این امکان را می دهد تا با تکرار مجموعه دستورالعمل ها با ورودی های مختلف، مسائل را به شیوه ای زیبا و کارآمد حل کنیم.
1- بازگشت مستقیم
بازگشت مستقیم اساسی ترین نوع بازگشت است که در آن یک تابع مستقیماً خود را فراخوانی می کند. این مستلزم تقسیم یک مسئله مشکل ساز به مسائل فرعی کوچکتر است تا زمانی که یک مورد پایه به دست آید، که منجر به خاتمه می شود.
تابع بازگشتی خود را با ورودی های مختلف فراخوانی می کند و اجرای مجموعه ای از دستورالعمل ها را قادر می سازد تکرار شوند. هر فراخوانی بر روی مورد قبلی استوار می شود و به تدریج به حالت پایه نزدیک می شود که باعث پایان بازگشت مجدد می شود.
بیایید این مثال را بررسی کنیم.
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
4- بازگشت درخت
وقتی یک تابع به چندین فراخوان بازگشتی منشعب می شود، وارد دنیای بازگشت درخت می شویم. یک تابع در بازگشت درختی، فراخوانی های بازگشتی زیادی ایجاد می کند، که هر کدام یک مشکل فرعی جداگانه را حل می کند، درست مانند شاخه های یک درخت.
این ساختار انشعاب امکان بررسی همزمان چندین مسیر را فراهم می کند و به طور موثر مسائل پیچیده را به اجزای کوچکتر و مرتبط با یکدیگر تجزیه می کند.
مثال:
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
result = fibonacci(6)
print(result)
خروجی:
8
5-بازگشت تو در تو
بازگشت تو در تو درجه هیجان انگیزی از پیچیدگی را به جهان بازگشتی اضافه می کند. در این شکل از بازگشت، یک تابع یک فراخوان بازگشتی را به عنوان آرگومان در یک فراخوان بازگشتی دیگر ترکیب می کند.
فراخوانی بازگشتی داخلی بر روی مقداری عمل می کند که به فراخوانی بازگشتی بیرونی وابسته است. پیچیدگی با هر فراخوانی تودرتو افزایش مییابد و به الگوی جالبی از تماسهای بازگشتی تودرتو ختم میشود.
مثال:
def nested_recursion(n):
if n > 100:
return n - 10
return nested_recursion(nested_recursion(n + 11))
result = nested_recursion(95)
print(result)
یافته ها:
91
6- بازگشت دم
بازگشت دم یک تکنیک بهینه سازی برای الگوریتم های بازگشتی است که می تواند عملکرد آنها را بهبود بخشد. فراخوانی بازگشتی به عنوان عمل نهایی یک تابع با بازگشت دنباله ظاهر میشود.
از آنجایی که پس از فراخوانی بازگشتی هیچ عملیات برجسته ای وجود ندارد، کامپایلر یا مفسر می تواند بازگشت را با یک پرش ساده جایگزین کند.
این رویکرد بهینهسازی که به عنوان بهینهسازی تماس دنباله شناخته میشود، نیاز به هر تماس بازگشتی برای حفظ یک قاب پشته را کاهش میدهد و در نتیجه باعث افزایش سرعت و استفاده کمتر از حافظه میشود.
مثال:
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
7-بازگشت غیر دم
بر خلاف بازگشت دم، بازگشت غیر دنباله شامل فعالیت های اضافی است که پس از فراخوانی بازگشتی در یک تابع انجام می شود. قبل از انجام هر گونه اقدام دیگری، هر تماس بازگشتی باید تکمیل و بازگردد.
در نتیجه، تا زمانی که به حالت پایه برسد و بازگشت به پایان برسد، مجموعه ای از عملیات برجسته حفظ می شود. بازگشت غیر دم اغلب از حافظه بیشتری استفاده می کند و کارایی کمتری نسبت به بازگشت دم دارد، اما همچنان ابزار مفیدی برای مقابله با مسائل مختلف است.
مثال:
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
بسته شدن
بازگشت یک مفهوم جذاب در برنامه نویسی است. این به ما اجازه می دهد تا با مشکلات پیچیده به شیوه ای بازگشتی و خودارجاعی مقابله کنیم.
روشی متمایز برای فکر کردن و حل مشکلات ارائه می دهد و آنها را به بخش های کوچکتر و قابل کنترل تر تقسیم می کند. با این حال، هنگام کار با بازگشت، توجه به برخی نکات ضروری است.
شما باید موارد پایه مناسبی را شناسایی کنید که به پایان بازگشت اجازه می دهد. اگر آنها وجود نداشته باشند، تابع ممکن است برای همیشه به فراخوانی خود ادامه دهد.
دوم، بر اساس سناریوی موجود، انتخاب نوع بازگشت مناسب می تواند به راه حل های کارآمدتر و ظریف تر منجر شود. سعی کنید برای مشکلی که در دست دارید بهترین کار را پیدا کنید. هنگام کار با اعماق بازگشت گسترده، از خطرات احتمالی مانند سرریز پشته آگاه باشید.
پاسخ دهید