PDA

View Full Version : سوال: لطفا توابع بازگشتی را به من یاد بدهید! ممنون



Parham.D
یک شنبه 29 فروردین 1389, 07:32 صبح
سلام دوستان عزیز و اساتید گرام.

درباره توابع بازگشتی جستجو کردم، اما مطلبی که آموزشی باشد پیدا نکردم. لصفا اگر لینکی دارید برایم قرار دهید، یا از روی کد زیر یاد بدهید که توابع بازگشتی چطور کار میکنند.




Function Factorial(ByVal number as long) as long
If number <= 1 then
Return 1
Else
Return number * Factorial(number - 1)
End If
End Factoria



سوال من این است که مگر Return مقدار مشخص شده جلوی خود را ارسال نمیکند؟! با این حساب وقتی در نهایت شرط پایه بررسی میشود مقدار 1 ارسال میشود، نه مقداری که در خط بازگشتی کد محاسبه شده. وقتی شرط پایه درست باشد دیگر Return بعد از Else نباید اجرا شود. حتما یک جای کار اشکال دارم. در نهایت اینکه به نظر من می‏آید 1 باید ارسال شود نه Return دوم. لطفا من را راهنمایی کنید که دقیقا چطور کار میکند.

سپاس از لطف شما . . .

hero4000
یک شنبه 29 فروردین 1389, 08:30 صبح
دوست عزيز دستور شما که مشکلي نداره و درست کار ميکنه البته يکم توي تعريف تابع تغييرات دادم و به شکل زير نوشتم و درست هم کار کرد

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MsgBox(Factorial(5))
End Sub
Private Function Factorial(ByVal number As Long) As Long
If number <= 1 Then
Return 1
Else
Return number * Factorial(number - 1)
End If
End Function
من که نفهميدم مشکل شما کجاست
کد بالا جواب 120 رو به من داد که درست هم هست

salehbagheri
یک شنبه 29 فروردین 1389, 08:47 صبح
به توابعي كه خودشون رو به طور مستقيم يا غير مستقيم فراخواني كنند توابع بازگشتي ميگن!


سوال من این است که مگر Return مقدار مشخص شده جلوی خود را ارسال نمیکند؟! با این حساب وقتی در نهایت شرط پایه بررسی میشود مقدار 1 ارسال میشود، نه مقداری که در خط بازگشتی کد محاسبه شده. وقتی شرط پایه درست باشد دیگر Return بعد از Else نباید اجرا شود. حتما یک جای کار اشکال دارم. در نهایت اینکه به نظر من می‏آید 1 باید ارسال شود نه Return دوم. لطفا من را راهنمایی کنید که دقیقا چطور کار میکند.

منظورتون رو متوجه نشدم!

vcldeveloper
یک شنبه 29 فروردین 1389, 10:46 صبح
درباره توابع بازگشتی جستجو کردم، اما مطلبی که آموزشی باشد پیدا نکردم. لصفا اگر لینکی دارید برایم قرار دهید، یا از روی کد زیر یاد بدهید که توابع بازگشتی چطور کار میکنند.
در ویکیپدیا توضیح خوبی درباره توابع بازگشتی، کاربردهایشان، و انواع شان داده شده؛ که به فارسی هم ترجمه شده:
http://fa.wikipedia.org/wiki/%D8%AA%D9%88%D8%A7%D8%A8%D8%B9_%D8%A8%D8%A7%D8%B2% DA%AF%D8%B4%D8%AA%DB%8C


سوال من این است که مگر Return مقدار مشخص شده جلوی خود را ارسال نمیکند؟! با این حساب وقتی در نهایت شرط پایه بررسی میشود مقدار 1 ارسال میشود، نه مقداری که در خط بازگشتی کد محاسبه شده. وقتی شرط پایه درست باشد دیگر Return بعد از Else نباید اجرا شود. حتما یک جای کار اشکال دارم. در نهایت اینکه به نظر من می‏آید 1 باید ارسال شود نه Return دوم.
Return اول شما فقط زمانی اجرا میشه که مقدار ورودی شما 1 یا کمتر از 1 باشه، پس اگر مقدار ورودی شما بیش از 1 باشه، Return دوم اجرا میشه. Return دوم هم همان تابع را مجددا فراخوانی میکنه، ولی قبلش یک واحد مقدار ورودی را کاهش میده. این کار اونقدر ادامه پیدا میکنه تا مقدار ورودی تابع به 1 برسه. وقتی به 1 رسید، Return اول فراخوانی میشه.

در کد شما، اگر بخوایم فاکتوریل 5 را حساب کنیم، کد به این شکل اجرا میشه:

5 بزرگتر از 1 هست، پس Return اول اجرا نمیشه.
خروجی تابع توسط Return دوم به صورت 5 ضربدر فاکتوریل 4 محاسبه میشه.
پس تابع یک بار دیگه فراخوانی شده. فراخوانی قبلی تابع همچنان منتظر نتیجه فراخوانی دوم هست.
فاکتوریل 4 میشه 4 ضربدر فاکتوریل 3.
پس تابع برای بار سوم فراخوانی شده، و فراخوانی فاکتوریل 4 منتظر نتیجه فراخوانی فاکتوریل 3 هست.
فاکتوریل 3 میشه 3 ضربدر فاکتوریل 2.
تابع برای بار چهارم فراخوانی شده، و فراخوانی فاکتوریل 3 منتظر نتیجه فراخوانی فاکتوریل 2 هست.
فاکتوریل 2 میشه 2 ضربدر فاکتوریل 1.
تابع برای بار پنجم فراخوانی شده، و فراخوانی فاکتوریل 2 منتظر نتیجه فراخوانی فاکتوریل 1 هست.

تا اینجای کار تابع فاکتوریل 5 بار به صورت تو در تو فراخوانی شده، و نتیجه هر فراخوانی وابسته به نتیجه فراخوانی انجام شده در داخل آن هست؛ یعنی فاکتوریل 5 منتظر فاکتوریل 4 منتظر فاکتوریل 3 منتظر فاکتوریل 2 و منتظر فاکتوریل 1 هست.

حالا برای ورودی 1، مقدار Return اول برگشت داده میشه که همان 1 هست، پس مقدار فاکتوریل 1 میشه 1.
اگر فاکتوریل 1 بشه 1، پس فاکتوریل 2 هم که منتظر نتیجه فاکتوریل 1 بود، میشه 2 ضربدر 1؛ یعنی 2.
وقتی فاکتوریل 2 بشه 2، پس فاکتوریل 3 هم که منتظر نتیجه فاکتوریل 2 بود، میشه 3 ضربدر 2؛ یعنی 6.
وقتی فاکتوریل 3 بشه 6، پس فاکتوریل 4 هم که منتظر نتیجه فاکتوریل 3 بود، میشه 4 ضربدر 6؛ یعنی 24.
وقتی فاکتوریل 4 بشه 24، پس فاکتوریل 5 هم که منتظر نتیجه فاکتوریل 4 بود، میشه 5 ضربدر 24، یعنی 120.
پس ما موفق شدیم با 5 فراخوانی تو در توی تابع فاکتوریل، مقدار فاکتوریل 5 را به دست بیاریم.

Parham.D
دوشنبه 30 فروردین 1389, 07:25 صبح
با سپاس بسیار از همه دوستان، به ویژه آقای کشاورز.

تا اینجا که من فهمیدم، تابع به صورت مکرر خود را صدا می‏زند و در هر بار فراخوانی مسئله کوچکتر می‏شود و یا اینکه جزئی‏تر محاسبه می‏شود. و همچنین تابع در مرحله بازگشت در بخش دیگری از حافظه قرار می‏گیرد (یعنی یک نمونه از خود را کپی میکند؟). تابع بازگشتی باید یک جا به پایان برسد، و آن زمانی است که شرط پایه برقرار شود یعنی :


If number <= 1 then
Return 1


چرا که فاکتوریل 1 خود 1 است. بخش فراخوانی به صورت بازگشتی را فهمیدم اما حالت پایه را درست نفهمیدم! زمانی که حالت پایه برقرار شد. مقدار Return 2 به محلی که تابع فراخوانی شده ارسال میشود، که از آن استفاده می‏کنیم. اما Retun 1 به کجا ارسال میشود؟ آیا به محلی که تابع اصلی فراخوانی شده؟ یا به آن نمونه که در جایی دیگر از حافظه قرار داده شده؟ کد درست است و صحیح کار میکند، اما به لحاظ تئوری نمی‏توانم بفهمم چطور حالت پایه باعث توقف فراخوانی میشود.بر اساس گفته آقای کشاورز، Return اول در صورت اجرا می‏شود. 1. مقدار ورودی 1 یا 0 باشد، که خب تکلیف معلوم است. 2. این کار اونقدر ادامه پیدا میکنه تا مقدار ورودی تابع به 1 برسه. وقتی به 1 رسید، Return اول فراخوانی میشه. همین جا هست که من هنگ میکنم!! :) در حالت دوم return 1 به کجا ارسال میشود و چطور جلوی فراخوانی مجدد را می‏گیر؟

امیدوارم درست توضیح داده باشم.

با سپاس از شما . . .

hero4000
دوشنبه 30 فروردین 1389, 09:55 صبح
دوست عزيز Return 1 به آخرين تابعي ارسال ميشود که آنرا فراخواني کرده

خوب از اينجا به بعد ديگه يکي يکي توابعي که اين توابع رو فراخواني کردند مقدار ميگيرند و به تابع قبلي خودشون تحويل ميدند تا به تابع اول که فراخواني شروع شده برسه

خوب اون تابع هم مقداري که دريافت کرد رو محاسبه ميکنه و به شما تحويل ميده

به همين راحتي :قهقهه:

vcldeveloper
دوشنبه 30 فروردین 1389, 17:05 عصر
و همچنین تابع در مرحله بازگشت در بخش دیگری از حافظه قرار می‏گیرد (یعنی یک نمونه از خود را کپی میکند؟).
نه، تابع در هر بار فراخوانی در محل دیگه ایی از حافظه قرار نمیگیره. تابع سر جای خودش هست. برای اینکه متوجه بشید چطور فراخوانی انجام میشه، باید بدونید در زمان فراخوانی یک تابع، کامپایلر چطور عمل میکنه. به طور ساده؛ وقتی در کد شما یک تابع فراخوانی میشه، کامپایلر پارامترهای ارسالی به اون تابع را وارد Stack میکنه، متغیرهای محلی تعریف شده در اون تابع هم وارد Stack میشند، سپس اجرای برنامه به ابتدای کدهای تابع پرش میکنه. وقتی کدهای تابع اجرا شدند، متغیرهایی که قبل از ورود به کدهای تابع در Stack ذخیره شده بودند، از Stack خارج میشند، و اجرای برنامه به خط بعد از فراخوانی اولیه تابع در برنامه شما پرش میکنه.

در یک تابع برگشتی، هر زمان که شما همان تابع را فراخوانی می کنید، همین روال دائما تکرار میشه. با این تفاوت که در هر بار بازگشت، مقادیر پارامترهایی که برای فراخوانی آن تابع در Stack قرار می گیرند، متفاوت خواهد بود. هر زمان که هر کدام از توابع کارشان تمام شد، کنترل اجرا به کدی که آن تابع را فراخوانده بود بر میگرده.

پس در مثال بالا، وقتی فاکتوریل 1 کارش تمام میشه، چون توسط تابع فاکتوریل 2 فراخوانی شده بود، نتیجه اش به همان تابع فاکتوریل 2 برمیگرده. با اتمام کار فاکتوریل 2، نتیجه اش به تابع فاکتوریل 3 برمیگرده. با اتمام کار تابع فاکتوریل 3، نتیجه اش به تابع فاکتوریل 4 برمیگرده...همینطور تا برسیم به تابع فاکتوریل 5. بعد از اتمام کار تابع فاکتوریل 5، کنترل اجرای برنامه به کدی برمیگرده که تابع فاکتوریل 5 را فراخوانی کرده. مثلا اگر شما در رویداد OnClick یکی از دکمه های برنامه تان تابع فاکتوریل با مقدار پارامتر 5 را فراخوانی کرده باشید، نتیجه تابع نهایتا به کد مربوط به همان رویداد بر میگرده.

raha_pc
جمعه 31 مرداد 1393, 20:27 عصر
کجا می شه نمونه سوالات تابع بازگشتی رو بیابم؟