11.02.2014 Views

ﻣﺒﺎﻧﯽ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﯽ ﺟﻠﺴﻪ ﯼ ﻫﺠﺪﻫﻢ -۱۱( -۱۳ ۱۳۹ )

ﻣﺒﺎﻧﯽ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﯽ ﺟﻠﺴﻪ ﯼ ﻫﺠﺪﻫﻢ -۱۱( -۱۳ ۱۳۹ )

ﻣﺒﺎﻧﯽ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﯽ ﺟﻠﺴﻪ ﯼ ﻫﺠﺪﻫﻢ -۱۱( -۱۳ ۱۳۹ )

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

مبانی برنامه نويسی<br />

جلسه ی هجدهم<br />

(۱۱-۱۳-۱۳۹)<br />

دانشگاه شهيد بهشتی<br />

پاييز<br />

دانشکده ی مهندسی برق و کامپيوتر<br />

احمد محمودی ازناوه<br />

۱۳۹۱<br />

http://faculties.sbu.ac.ir/~a_mahmoudi/


فهرست مطالب<br />

•<br />

•<br />

•<br />

•<br />

•<br />

ارسال با ارجاع<br />

تابع بازگشتي<br />

استقرا<br />

روابط بازگشتي<br />

تابع بازگشتي<br />

ويرايش جديد با كمك هاي آقاي<br />

‏«محمدرضا بهرامي»‏ تهيه شده است.‏<br />

مبانی برنامه نويسی<br />

2


‏•مروي بر جلسهي پيش<br />

ارسال از طريق مقدار<br />

به صورت معمول،‏ هنگامي كه تابعي فراخواني<br />

مي شود،‏ آرگومان هاي ورودي به صورت ارسال از<br />

طريق مقدار در نظر گرفته مي شوند.‏<br />

در اين حالت يك كپي از مقادير گرفته شده،‏<br />

فرآيند ها به روي كپي مورد نظر اعمال مي گردند.‏<br />

در بسياري موارد هنگامي كه مقادير ارسالي<br />

حجم بالا باشند،‏ كپي به حافظه ي زيادي نياز<br />

مقرون به صرفه نيست.‏<br />

call by value<br />

داراي<br />

دارد و<br />

•<br />

•<br />

•<br />

راه حل ارسال از طريق ارجاع<br />

3


‏•مروي بر جلسهي پيش<br />

ارسال با ارجاع<br />

–<br />

متغير ارجاعي نام ديگري براي متغير اصلي است.‏<br />

به همين علت هر تغييري كه به<br />

ارجاعي اعمال گردد،‏ متغير اصلي نيز<br />

كرد.‏<br />

روي<br />

تغيير<br />

متغير<br />

خواهد<br />

در مواردي كه نياز باشد تغييرات به روي متغير<br />

اصلي نيز صورت پذيرد آرگومان هاي تابع را به<br />

صورت ‏«ارجاع»‏ در نظر مي گيريم.‏<br />

مثال:‏ تابعي كه دو عدد را جا به جا مي كند.‏<br />

call by reference<br />

•<br />

•<br />

•<br />

4


•<br />

‏•مروي بر جلسهي پيش<br />

ارسال با ارجاع<br />

‏(ادامه...)‏<br />

متغير ارجاعي همانند<br />

مي شود و تنها يك<br />

در نظر گرفته مي شود.‏<br />

«&»<br />

متغير refVar يك رفرنس به int خواهد بود<br />

Ampersand<br />

متغير معمولي تعريف<br />

براي نشان دادن نوع ارجاع<br />

prototype<br />

5


‏•مروي بر جلسهي پيش<br />

ارسال با ارجاع<br />

‏(مثال)‏<br />

هنگامي كه با متغير ارجاعي كار مي كنيم فرآيند به<br />

روي متغيري كه با آن ارجاع مي شود صورت مي گيرد<br />

6


‏•مروي بر جلسهي پيش<br />

ارسال با ارجاع<br />

‏(مثال)‏<br />

7


ارسال با ارجاع ‏(نکات)‏<br />

تنها ‏«متغير ها»‏ از طريق<br />

گردند.‏<br />

ارسال عبارات و ثابت ها<br />

با خطا مواجه مي كند.‏<br />

ارجاع مي توانند ارسال<br />

از طريق ارجاع برنامه را<br />

•<br />

•<br />

به دليل تغيير متغير خارج<br />

طريق ارجاع،‏ اين پتانسيل<br />

كه به صورت سهوي مقادير<br />

از تابع هنگام ارسال از<br />

به برنامه داده مي شود<br />

تغيير يابد.‏<br />

•<br />

تنها در مواردي كه نياز است از ارسال به طريق ارجاع استفاده كنيد<br />

8


ارسال با ارجاع ‏(نکات)‏<br />

–<br />

چه زمان ارسال از طريق ارجاع داشته باشيم چه<br />

زمان از طريق مقدار؟<br />

هنگامي كه آرگومان ورودي ثابت است،‏<br />

طريق مقدار صورت مي گيرد ‏(تنها متغيرها<br />

ارجاع قابليت ارسال دارند)‏<br />

ارسال از<br />

از طريق<br />

ارسال از طريق مقدار<br />

•<br />

هنگامي كه مقدار يك متغير نمي بايد در جريان<br />

فراخواني تابع تغيير كند ارسال از طريق مقدار است.‏<br />

هنگامي كه خروجي تنها يك<br />

بازگشت داده مي شود<br />

است.‏<br />

return<br />

متغير است از طريق<br />

و ارسال از طريق مقدار<br />

–<br />

–<br />

9


ارسال با ارجاع ‏(نکات -<br />

ادامه...)‏<br />

–<br />

–<br />

–<br />

چه زمان ارسال از طريق ارجاع داشته باشيم چه<br />

زمان از طريق مقدار؟<br />

هنگامي كه بيش از يك مقدار بناست تغيير داده شود<br />

‏(چون تنها يك مقدار بازگشتي مي توان داشت)،‏ ارسال<br />

از طريق ارجاع صورت مي گيرد.‏<br />

هنگامي كه داده ي اصلي مقدار بزرگي است،‏ كپي آن<br />

فرآيندي منطقي نيست،‏ ارسال به شيوه ي ارجاع<br />

صورت مي گيرد.‏<br />

تغيير<br />

تابع ماهيت هنگامي كه باشد.‏<br />

آرگومان هاي ورودي<br />

تابع Swap<br />

•<br />

10


ارسال با ارجاع(مثال-‏<br />

تغییر روی آرگومان های ورودی)‏<br />

11


‏(تغيير روی آرگومان های ورودی)‏<br />

12


ارسال با ارجاع ‏(مثال-‏<br />

تغییر روی آرگومان های ورودی)‏<br />

13


14<br />

تغيير روی آرگومان های ورودی


15<br />

مثال


16<br />

مثال


ارسال با ارجاع ‏(مثال-‏<br />

چند خروجی)‏<br />

استفاده از ارجاع هنگامي كه بيش از يك خروجي در<br />

تابع نياز است:‏<br />

•<br />

17


ارسال به وسيله ی ارجاع ثابت<br />

يكي از مواردي كه ارسال به وسيله ي ارجاع<br />

پيشنهاد داده مي شود زماني است كه آرگومان<br />

ارسالي حجيم است.‏<br />

در اين صورت است كه از كپي كردن آرگومان<br />

جلوگيري مي شود و برنامه بازده بيشتري خواهد<br />

داشت.‏<br />

ممكن است تابع آرگومان را ناخواسته تغيير دهد<br />

•<br />

•<br />

پيشنهاد<br />

ارسال ارجاع ثابت<br />

18


19<br />

مثال ‏(ارسال به وسيله ی ارجاع ثابت)‏


مثال ‏(ارسال به وسيله ی ارجاع ثابت)‏<br />

اگر سعي كنيد ارجاعي را كه ثابت است در تابع<br />

تغيير دهيد،‏ با خطاي كامپايلري مواجه مي شويد<br />

•<br />

error C3892: 'z' : you cannot assign to a variable that is const<br />

20


exit function<br />

تابع خروج<br />

استفاده از تابع<br />

خارج شويم.‏<br />

exit<br />

main<br />

سبب مي شود كه از برنامه<br />

return<br />

return<br />

main<br />

هنگامي كه در به دستور مي رسيم<br />

برنامه پايان مي يابد.‏ استفاده از در توابع<br />

ديگر سبب مي شود كنترل برنامه به ‏(يا<br />

تابعي كه تابع فعلي را صدا زده است)‏ بازگردد.‏<br />

در بعضي موارد نياز است در هر موقعيتي از برنامه<br />

خارج شويم.‏<br />

تابع از هر exit<br />

برنامه مي گردد.‏<br />

كجا فراخواني شود،‏ سبب خروج از<br />

•<br />

•<br />

•<br />

•<br />

21


22<br />

مثال ‏(تابع خروج)‏


Scope های تودرتو و موازی<br />

23


های تودرتو و موازی<br />

‏(ادامه...)‏<br />

Scope<br />

هر متغير تنها در محدوده ي خويش معتبر است.‏<br />

مقدار هر متغير سراسري با تعريف در محدوده ي<br />

جديد override مي گردد.‏<br />

•<br />

•<br />

استفاده<br />

از اپراتور<br />

باعث مي شود متغير<br />

نشان داده شود<br />

.<br />

global<br />

::<br />

Scope resolution operator<br />

24


توابع بازگشتی<br />

توابع بازگشتی<br />

Overhead<br />

•<br />

•<br />

–<br />

–<br />

–<br />

بالا به دليل فراخواني تابع<br />

نگاه داشتن آدرس بازگشتي،‏ ايجاد متغير ها<br />

مديريت حافظه<br />

در هر بار فراخواني تابع مقداري حافظه اختصاص داده شده مصرف<br />

مي شود.‏<br />

پياده سازي با دستورالعمل هاي كم تر همراه با ظرافت و خوانايي<br />

بهتر برنامه


مروری بر تابع<br />

در جلسات گذشته در مورد تابع و دلايل استفاده از آن<br />

صحبت كرديم.‏<br />

گفتيم كه يك تابع به ازاي هر ترتيب از آرگومان هاي<br />

دارد؛<br />

ورودي حداكثر يك خروجي رسمي<br />

با اين حال تاكنون اجباري در استفاده از توابع براي حل<br />

مسائل نداشتيم و هر سوالي كه در مورد آن صحبت<br />

كرديم،‏ مستقل از پياده سازي به وسيله ي توابع نيز،‏ قابل<br />

حل بوده است.‏<br />

(return value)<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

26


ecursive function<br />

توابع بازگشتی<br />

–<br />

–<br />

–<br />

در اينجا قصد داريم ‏«توابع بازگشتي»‏ را به عنوان ابزاري<br />

براي حل دسته اي وسيع از مسائل معرفي كنيم.‏ اين ابزار<br />

قدرتمند حل بسياري از مسائل را ممكن كرده يا<br />

پياده سازي كد را بسيار ساده مي كند.‏<br />

به جهت اهميت اين مبحث و دخيل بودن مباني رياضي<br />

مهم ابتدا برخي از اين مباحث را اندكي تشريح مي كنيم.‏<br />

مطالب مورد بحث به ترتيب عبارت اند از:‏<br />

استقراي رياضي<br />

روابط بازگشتي<br />

طراحي توابع بازگشتي<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

27


اصل استقرای رياضی<br />

همه شما در دبيرستان با استقراي رياضي آشنا شده ايد و<br />

از آن براي اثبات برخي از احكام رياضي استفاده كرده ايد.‏<br />

به طور مثال:‏<br />

«1»<br />

ثابت كنيد كه هر عدد طبيعي بزرگ تر از را مي توان به<br />

عوامل اول تجزيه كرد.‏<br />

همان طور كه به ياد داريد براي حل يك مسئله توسط<br />

استقرا به يك پايه و يك فرض نيازمنديم.‏ سپس با<br />

استفاده از گام استقرايي و نتيجه گرفتن حكم براي يك<br />

عدد طبيعي خارج از مجموعه فرض،‏ حل را كامل<br />

مي كرديم.‏ يعني از پايه بديهي حكم را براي بقيه اعداد<br />

تعميم مي داديم.‏<br />

•<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

28


حل<br />

پايه ي استقرا:‏<br />

بديهي است كه در حالت = 2 n<br />

فرض قوي استقرا:‏<br />

همه چيز صحيح است.‏<br />

فرض مي كنيم براي تمام اعداد كوچك تر از k مسئله درست<br />

است.‏<br />

گام استقرايي:‏<br />

:<br />

عدد 1+k<br />

يا اول است يا مركب<br />

اگر اول باشد:‏ چون عدد اول است مي توان آن را به صورت<br />

1*(1+k) نوشت و اثبات تمام است.‏<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

29


حل ‏(ادامه...)‏<br />

اگر مركب باشد:‏<br />

چون اين عدد مركب است پس حتما عددي مانند p كه<br />

اولا،‏ اول است و ثانيا از 1+k كوچك تر است وجود دارد به<br />

طوري كه:‏<br />

k+1 = p*q<br />

كه q<br />

عددي كوچك تر از 1+k است و طبق فرض قوي<br />

استقرا مي توان q را به صورت حاصل ضرب اعداد اول<br />

نوشت و در اينجا كار تمام است.‏<br />

•<br />

مبانی برنامه نويسی<br />

30


آشنايی با روابط<br />

بازگشتی<br />

گاهي قادر به حل مسائل به خصوص مسائل<br />

شمارشي به صورت صريح نيستيم ولي در صورت<br />

داشتن جواب مسئله در حالات ديگر به راحتي قادر<br />

به حل سوال در حالت جديد خواهيم بود.‏<br />

به مثال زير كه يك مسئله ي شمارشي است توجه<br />

كنيد:‏<br />

10 سكه در اختيار داريد كه هر يك داري دو طرف سفيد و سياه<br />

هستند،‏ با اين فرض كه هيچ دو سكه سياهي كنار هم نباشند.‏<br />

تعداد حالت هاي ممكن چينش را حساب كنيد؟<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

31


روابط بازگشتی ‏(مثال)‏<br />

–<br />

–<br />

اگر به صورت بندي مسئله بيشتر دقت كنيم مي توانيم<br />

بهتر آن را درك كنيم.‏<br />

اگر كمي بيشتر به مسئله فكر كنيم درخواهيم يافت<br />

كه مجموعه جواب هاي مسئله به دو دسته افراز<br />

مي شوند:‏<br />

دسته ي اول شامل اعضايي هستند كه اولين سكه در آن ها<br />

به رنگ سفيد است.‏<br />

دسته دوم شامل آن هايي كه با سياه آغاز مي شوند.‏<br />

بديهي است كه عناصر دوم از دسته دوم حتما به رنگ<br />

سفيد هستند ‏(چرا؟)‏<br />

قبل از ادامه ي داستان(!)‏ توجه شما را به اين حالات<br />

بديهي جلب مي كنيم:‏<br />

•<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

32


مثال ‏(ادامه...)‏<br />

فرض كنيد كه تعداد جواب ها براي تعداد n سكه<br />

با نشان داده شوند.‏ در اين صورت:‏<br />

• F(1) = 2<br />

• F(2) = 3<br />

• ….<br />

F(n)<br />

بياييد كمي به عقب برگرديم،‏ به استقراي رياضي!‏<br />

مانند استقرا فرض كنيد حل مسئله براي تمام<br />

اعداد كوچك تر از n ممكن بوده و جواب را داريم!‏<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

33


مثال ‏(ادامه...)‏<br />

آيا مي شود جواب را محاسبه كرد؟<br />

گفتيم جواب ها چگونه افراز خواهند شد؛ اگر حالت<br />

اول را در نظر بگيريد با داشتن همه<br />

جواب ها را خواهيد داشت:‏<br />

F(n-1)<br />

•<br />

•<br />

F(n-1)<br />

? ? ….<br />

F(n)<br />

مبانی برنامه نويسی<br />

n - 1<br />

34


مثال ‏(ادامه...)‏<br />

–<br />

اما از طرفي ديديم كه در حالت دوم مجبور به<br />

گذاشتن سفيد در خانه دوم هستيم پس:‏<br />

F(n-2)<br />

اگر حاصل را داشته باشيم قادر به محاسبه<br />

اين مجموع نيز هستيم(افزودن تصاوير):‏<br />

•<br />

F(n-2)<br />

? ? ….<br />

F(n)<br />

n - 2<br />

مبانی برنامه نويسی<br />

35


مثال ‏(ادامه...)‏<br />

بنابراين براي جوابمان خواهيم داشت:‏<br />

F(n) = F(n-1) + F(n-2)<br />

در اينجا گام استقرايي ما براي رسيدن به جواب<br />

يك عمل جمع است!‏<br />

F(n-2)<br />

F(n-1)<br />

•<br />

•<br />

F(n)<br />

مبانی برنامه نويسی<br />

36


مثال ‏(ادامه...)‏<br />

پس جواب خواهد شد:‏<br />

• F(1) = 2 F(2) = 3<br />

• F(3) = 5 F(4) = 8<br />

• F(5) = 13 F(4) = 21<br />

• F(7) = 34 F(8) = 55<br />

• F(9) = 89<br />

•<br />

F(10) = 144<br />

مبانی برنامه نويسی<br />

37


الگوريتم های تکراری<br />

براي پياده سازي الگوريتم هايي كه فرايندي را تكرار<br />

مي كنند معمولاً‏ به دو شيوه عمل مي شود:‏<br />

توابع بازگشتي<br />

Overhead<br />

–<br />

•<br />

–<br />

بالا به دليل فراخواني تابع<br />

نگاه داشتن آدرس بازگشتي،‏ ايجاد متغير ها<br />

مديريت حافظه<br />

•<br />

–<br />

استفاده از حلقه ها<br />

استفاده از توابع بازگشتي<br />

در هر بار فراخواني تابع مقداري حافظه اختصاص داده شده<br />

مصرف مي شود.‏<br />

پياده سازي با دستورالعمل هاي كم تر همراه با ظرافت<br />

•<br />

•<br />

و خوانايي بهتر برنامه<br />

38<br />

مبانی برنامه نويسی


A recursive function is one that calls itself.<br />

توابع بازگشتی<br />

ساختار توابع بازگشتي به گونه اي است كه خود را<br />

فراخواني مي نمايند.‏<br />

فراخواني مي تواند به صورت مستقيم و يا<br />

غيرمستقيم از طريق توابع ديگر صورت پذيرد.‏<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

39


توابع بازگشتی ‏(ادامه...)‏<br />

تابع زير در<br />

فرامي خواند:‏<br />

فراخواني بار هر<br />

را خود مجدداً‏<br />

•<br />

در آيا مشكلي<br />

تابع مي بينيد؟<br />

•<br />

هيچ راه كاري براي توقف تابع تعبيه نشده است.‏<br />

تابع مانند حلقه ي بي پايان عمل مي كند.‏<br />

مبانی برنامه نويسی<br />

40


توابع بازگشتی ‏(ادامه...)‏<br />

براي كاربردي بودن تابع بازگشتي مي بايد به گونه اي<br />

راهي براي توقف تابع در نظر گرفت:‏<br />

•<br />

مبانی برنامه نويسی<br />

41


مثال<br />

مبانی برنامه نويسی<br />

42


توابع بازگشتی ‏(ادامه...)‏<br />

مبانی برنامه نويسی<br />

43


Function Calling<br />

پيش تر در مورد صدا كردن يك تابع،‏ ارسال آرگومان و بازگرداندن<br />

خروجي صحبت شد.‏<br />

•<br />

A complete guide to programming in C++<br />

مبانی برنامه نويسی<br />

44


مثال<br />

مبانی برنامه نويسی<br />

45


توابع بازگشتی ‏(ادامه...)‏<br />

تابع بازگشتي با شكستن فرآيند ي تكراري به حل<br />

مساله كمك مي كند.‏<br />

اجراي فرآيند تا زماني كه به يك<br />

برسيم ادامه خواهد داشت.‏<br />

در<br />

«base case»<br />

base case<br />

مثال قبل زماني است كه پارامتر<br />

برابر با صفر است.‏<br />

اين صورت فرآيند فراخواني متوقف مي شود.‏<br />

time<br />

در<br />

•<br />

•<br />

•<br />

•<br />

مبانی برنامه نويسی<br />

46


توابع بازگشتی ‏(ادامه...)‏<br />

مبانی برنامه نويسی<br />

47


تمرين<br />

• خروجي برنامه ي زير چيست؟<br />

مبانی برنامه نويسی<br />

48


تمرين<br />

• خروجي برنامه ي زير چيست؟<br />

مبانی برنامه نويسی<br />

49

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!