تعریف دقیق الگوریتم و درک چرایی نیاز به آن پیش از نوشتن کد
شناخت کامل نمادهای استاندارد فلوچارت: بیضی، مستطیل، لوزی، متوازیالاضلاع و فلش
ترسیم فلوچارت برای سه مسئله کلاسیک: جابهجایی دو مقدار، یافتن بزرگترین و حل معادله درجه یک
تفاوت برنامهنویسی بدون تفکر الگوریتمی و برنامهنویسی با تفکر الگوریتمی
توانایی خواندن، تفسیر و ردیابی (Trace) فلوچارتهای موجود
الگوریتم چیست؟
یک الگوریتم (Algorithm) مجموعهای محدود، مشخص و ترتیبی از گامهاست که برای حل یک مسئله یا انجام یک کار طراحی شده است. به زبان سادهتر: الگوریتم «دستور پخت» حل مسئله است.
برای نمونه، الگوریتم تهیه یک چای ساده اینگونه است:
۱. آب را در کتری بریز.
۲. کتری را روی اجاق بگذار.
۳. صبر کن تا آب به جوش آید.
۴. یک قاشق چایخوری چای داخل فنجان بریز.
۵. آب جوش را روی چای بریز.
۶. صبر کن تا چای دم بکشد.
۷. اگر دوست داری، شکر اضافه کن.
این الگوریتم سه ویژگی کلیدی دارد که هر الگوریتمی باید داشته باشد:
محدود بودن: تعداد گامها مشخص و متناهی است.
قطعی بودن: هر گام بهطور روشن تعریف شده و ابهام ندارد.
ترتیبی بودن: گامها باید به ترتیب درست اجرا شوند.
در برنامهنویسی، الگوریتم قبل از کد نوشته میشود؛ چون کد فقط پیادهسازی الگوریتم به زبان کامپیوتر است. اگر الگوریتم درست نباشد، حتی بهترین کد هم نمیتواند مسئله را درست حل کند.
چرا به الگوریتم نیاز داریم؟
شاید بپرسید: «چرا مستقیم کد ننویسم؟» این یکی از بزرگترین اشتباهات تازهکارهاست. نوشتن کد بدون الگوریتم مثل ساختن خانه بدون نقشه است؛ ممکن است دیوارها بایستند، اما اتاقها به هم نمیخورند.
دلایل اصلی استفاده از الگوریتم:
۱. شفاف شدن ذهن: وقتی الگوریتم را مینویسید، در واقع مسئله را برای خودتان حل میکنید. دیگر با کد درگیر نیستید، با منطق درگیرید.
۲. کاهش خطا: یک الگوریتم روی کاغذ راحتتر بررسی و اصلاح میشود تا صد خط کد C++.
۳. استقلال از زبان: الگوریتم به C++، پایتون یا جاوا وابسته نیست. وقتی الگوریتم را داشته باشید، آن را به هر زبانی میتوانید پیاده کنید.
۴. ارتباط با دیگران: وقتی با همتیمیتان در مورد راهحل صحبت میکنید، در واقع دارید الگوریتم را بحث میکنید، نه کد را.
۵. پیدا کردن خطاهای منطقی زودتر: اگر در الگوریتم باگ باشد، در مرحله طراحی پیدا میشود نه در مرحله تست، که هزینه بسیار کمتری دارد.
قاعده طلایی: هرچه زودتر الگوریتم را روی کاغذ بیاورید، دیرتر در کد گیر میکنید.
نمادهای استاندارد فلوچارت
برای نمایش بصری الگوریتم از فلوچارت (Flowchart) استفاده میکنیم. فلوچارت از نمادهای استانداردی تشکیل شده که هر کدام معنای خاصی دارند. این نمادها بر اساس استاندارد بینالمللی فلوچارت (ISO 5807:1985 که اکنون منسوخ شده ولی همچنان مرجع قرارداد صنعتی روزآمد است) تعریف شدهاند و در سراسر جهان یکسان هستند.
نماد
شکل
معنا
مثال
● بیضی (Oval)
شروع/پایان
نقطه آغاز یا پایان برنامه
Start، End
▮ مستطیل (Rectangle)
پردازش
یک عمل محاسباتی یا انتساب
x ← -b/a، sum ← sum + i
◆ لوزی (Diamond)
تصمیم
یک پرسش بله/خیر
a ≠ 0؟، i <= n؟
▰ متوازیالاضلاع (Parallelogram)
ورودی/خروجی
دریافت داده از کاربر یا چاپ نتیجه
دریافت a, b، چاپ x
↓ فلش (Arrow)
جریان
جهت اجرای گامها
از یک گام به گام بعد
○ دایره
اتصال
پیوند بین قسمتهای مختلف فلوچارت
برای فلوچارتهای طولانی
در فلوچارت استاندارد، ورودی و خروجی هر دو در متوازیالاضلاع قرار میگیرند. برخی کتابها برای خروجی از نماد برگه (Document) استفاده میکنند، اما در این دوره برای سادگی، برای هر دو از متوازیالاضلاع استفاده میکنیم.
چرا نمادها مهماند؟ چون فلوچارت یک زبان بینالمللی است؛ وقتی شما فلوچارتی با نمادهای درست میکشید، هر برنامهنویسی در جهان میتواند آن را بخواند، حتی اگر زبانش با شما فرق کند.
کد بدون تفکر الگوریتمی در برابر کد با تفکر الگوریتمی
فرض کنید میخواهیم برنامهای بنویسیم که سه عدد بگیرد و بزرگترین را چاپ کند. برنامهنویس تازهکار مستقیم کد میزند و وسط کار گیر میکند؛ برنامهنویس حرفهای اول الگوریتم را مینویسد.
در سمت چپ (نادرست)، بدون طراحی قبلی شروع به نوشتن میکنیم و وسط کار میفهمیم که فراموش کردهایم مقدار اولیه بدهیم یا منطق اشتباه است. در سمت راست (درست)، اول الگوریتم روی کاغذ میآید و سپس کد بهسادگی از آن پیادهسازی میشود.
قاعده: الگوریتم سادهترین قدم است که اگر درست انجام شود، کد خودش میآید.
نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاحشده و استاندارد
کد صحیحcpp
چگونه فلوچارت را بخوانیم؟
خواندن فلوچارت مثل خواندن یک نقشه است. این مراحل را دنبال کنید:
۱. از بیضی «شروع» پیدا کن. همیشه یک فلوچارت با یک بیضی Start آغاز میشود.
۲. فلشها را دنبال کن. فلشها به شما میگویند کدام گام بعد از کدام میآید. هیچگاه خلاف جهت فلش نرو.
۳. وقتی به لوزی رسیدی، دو مسیر داری. هر لوزی یک پرسش است که پاسخ «بله» یا «خیر» دارد. روی هر فلش خروجی از لوزی باید برچسب بله/خیر نوشته شده باشد.
۴. در مستطیل، محاسبه انجام میشود. هر مستطیل یک انتساب یا عملیات است؛ متغیر سمت چپ مقدار جدید میگیرد.
۵. متوازیالاضلاع برای تعامل با کاربر است. یا چیزی از کاربر میگیریم یا چیزی به او نمایش میدهیم.
۶. در بیضی «پایان» متوقف شو. هر مسیر معتبر باید به یک بیضی End برسد.
یک فلوچارت خوب نباید هیچ فلش بدون مقصدی داشته باشد و هیچ مستطیل/لوزی نباید معلق بماند. هر عنصر باید در زنجیره اجرا باشد.
تمرین ذهنی: هر بار که فلوچارت میبینید، آن را قدمبهقدم با مقادیر واقعی در ذهن اجرا کنید. این کار را ردیابی (Tracing) مینامند و یکی از مهمترین مهارتهای برنامهنویسی است.
مسئله اول: جابهجایی دو مقدار (Swap)
این یکی از کلاسیکترین مسئلههای اولیه است. فرض کنید دو متغیر a و b داریم و میخواهیم مقادیرشان را عوض کنیم؛ یعنی اگر a = 7 و b = 5 بود، بعد از اجرا a = 5 و b = 7 شود.
اشتباه رایج تازهکارها:
main.cppcpp
این کار اشتباه است! چرا؟ چون در خط اول مقدار a از بین میرود و به مقدار b تبدیل میشود. وقتی در خط دوم b = a را اجرا میکنیم، در واقع داریم مقدار جدید a (که همان b قدیم است) را در b میریزیم؛ پس هر دو متغیر مقدار b قدیم را خواهند داشت.
راهحل: از یک متغیر کمکی t (مخفف temporary) استفاده میکنیم تا مقدار a را موقتاً نگه دارد:
۱. t ← a (مقدار a را در t ذخیره کن)
۲. a ← b (حالا میتوانیم a را با b بازنویسی کنیم)
۳. b ← t (مقدار t که همان a قدیم بود را در b بریز)
این الگوریتم مثل این است که میخواهیم محتویات دو لیوان آب را عوض کنیم؛ به یک لیوان سوم نیاز داریم تا آب یکی را موقتاً بریزیم.
فلوچارت: جابهجایی دو مقدار
flow.svg
پیادهسازی: جابهجایی دو مقدار
این کد معادل دقیق فلوچارت بالا است. به ترتیب سه انتساب دقت کنید: t = a، a = b، b = t. اگر این ترتیب به هم بریزد، جابهجایی درست انجام نمیشود.
برنامه کامل جابهجایی دو عدد با متغیر کمکی tcpp
$خروجی برنامه
do adad vared konid: 7 5
baad az jabejaei: a = 5, b = 7
در حال باز کردن ویرایشگر…
مسئله دوم: یافتن بزرگترین بین سه عدد
میخواهیم بزرگترین عدد بین a، b و c را پیدا کنیم. دو روش کلی وجود دارد:
روش اول: مقایسههای تودرتو (Nested If)
اگر a > b:
اگر a > c: بزرگترین a است.
وگرنه: بزرگترین c است.
وگرنه (یعنی b >= a):
اگر b > c: بزرگترین b است.
وگرنه: بزرگترین c است.
این روش درست کار میکند اما برای تعداد زیاد متغیرها طولانی میشود.
روش دوم: متغیر کمکی max (روش حرفهای)
۱. فرض کن max = a (اولین عدد را بهعنوان بزرگترین در نظر بگیر).
۲. اگر b > max، آنگاه max = b کن.
۳. اگر c > max، آنگاه max = c کن.
۴. max را چاپ کن.
مزیت روش دوم: برای ۴، ۵ یا ۱۰۰ عدد هم قابل تعمیم است؛ فقط کافی است در یک حلقه، تکتک اعداد را با max مقایسه کنیم. این همان الگویی است که در درسهای بعدی برای یافتن max بین n عدد از آن استفاده خواهیم کرد.
فلوچارت: یافتن بزرگترین بین سه عدد (روش متغیر max)
flow.svg
پیادهسازی: یافتن بزرگترین بین سه عدد
این کد معادل فلوچارت بالا است. max را با مقدار a مقداردهی اولیه میکنیم، نه با صفر. اگر max = 0 میگذاشتیم و همه اعداد منفی بودند، خروجی صفر میشد که غلط است. این یکی از تلههای کلاسیک است که در نسخه اولیه جزوه هم دیده میشد.
الگوی «اولین عدد بهعنوان مقدار اولیه max» — الگویی که در کل دوره استفاده میشودcpp
$خروجی برنامه
se adad vared konid: 4 9 2
bigitarin = 9
در حال باز کردن ویرایشگر…
مسئله سوم: حل معادله درجه یک a·x + b = 0
معادله درجه یک به فرم کلی a*x + b = 0 (که در جزوه بهصورت an + b = 0 نوشته شده) یکی از سادهترین معادلات ریاضی است. حل تحلیلی آن ساده است:
اگر a ≠ 0: جواب یکتاست و برابر x = -b / a.
اگر a = 0:
اگر b = 0: معادله به 0 = 0 تبدیل میشود، یعنی هر عددی جواب است (بینهایت جواب).
اگر b ≠ 0: معادله به b = 0 (مثلاً 5 = 0) تبدیل میشود، یعنی هیچ جوابی ندارد.
این مسئله فقط ریاضی نیست؛ یک الگوی مهم برنامهنویسی است: قبل از تقسیم، باید از صفر نبودن مخرج مطمئن شویم. اگر در C++ بر صفر تقسیم کنیم، برنامه با خطای زمان اجرا (Runtime Error) متوقف میشود.
پس الگوریتم کامل این است:
۱. a و b را از ورودی بگیر.
۲. اگر a ≠ 0:
x = -b / a را محاسبه کن.
x را چاپ کن.
وگرنه (یعنی a = 0):
اگر b = 0: پیام «بینهایت جواب» چاپ کن.
وگرنه: پیام «بدون جواب» چاپ کن.
نکته: در نسخه سادهشده جزوه، فقط حالت «بینهایت جواب» برای a = 0 در نظر گرفته شده بود. ما در اینجا نسخه کاملتری را پیاده میکنیم.
فلوچارت: حل معادله درجه یک (با کنترل خطای تقسیم بر صفر)
flow.svg
پیادهسازی: حل معادله درجه یک
در این کد از نوع double برای ضرایب و ریشه استفاده میکنیم تا تقسیم اعشاری درست انجام شود. اگر از int استفاده میکردیم، تقسیم -b / a تقسیم صحیح میشد و قسمت اعشاری حذف میگشت. این نکته را در درس متغیرها و انواع داده با جزئیات خواهیم دید.
کنترل کامل سه حالت: a ≠ 0، a = 0 و b = 0، a = 0 و b ≠ 0cpp
$خروجی برنامه
zarib a va b ra vared konid: 2 -6
rishe = 3
---
zarib a va b ra vared konid: 0 5
moadele javab nadarad
---
zarib a va b ra vared konid: 0 0
bi-nahayat javab (har x javab ast)
در حال باز کردن ویرایشگر…
ردیابی فلوچارت با مقادیر واقعی
برای اطمینان از درست کار کردن، فلوچارت حل معادله را با دو ورودی مختلف ردیابی (Trace) میکنیم.
حالت ۱: ورودی a = 2, b = -6
گام
شکل
عملیات
مقدار
۱
● شروع
آغاز
-
۲
▰ ورودی
دریافت a و b
a=2, b=-6
۳
◆ تصمیم
a ≠ 0؟
بله
۴
▮ پردازش
x = -b/a = -(-6)/2
x = 3
۵
▱ خروجی
چاپ x
«3»
۶
◎ پایان
پایان
-
حالت ۲: ورودی a = 0, b = 0
گام
شکل
عملیات
مقدار
۱
● شروع
آغاز
-
۲
▰ ورودی
دریافت a و b
a=0, b=0
۳
◆ تصمیم اول
a ≠ 0؟
خیر
۴
◆ تصمیم دوم
b = 0؟
بله
۵
▱ خروجی
چاپ پیام
«بینهایت جواب»
۶
◎ پایان
پایان
-
ردیابی یکی از مهمترین مهارتهای شماست. هر بار کدی نوشتید، با چند ورودی نمونه آن را در ذهن یا روی کاغذ اجرا کنید.
بهترین شیوهها برای ترسیم فلوچارت
برای کشیدن فلوچارت تمیز و خوانا، این قواعد را رعایت کنید:
از بالا به پایین، از چپ به راست بنویسید. این جهت طبیعی خواندن است.
هر گام فقط یک کار انجام دهد. اگر یک مستطیل چند کار میکند، آن را بشکنید.
لوزی فقط پرسش بله/خیر باشد. نه محاسبه، نه چاپ.
روی فلشهای خروجی از لوزی، برچسب «بله» و «خیر» بزنید. بدون این برچسبها، فلوچارت مبهم میشود.
همه مسیرها به یک بیضی پایان برسند. هیچ فلشی نباید معلق بماند.
برای حلقه، فلش بازگشت را واضح بکشید (معمولاً از پایین به بالا، با علامت ↻ یا کلمه «بازگشت»).
نام متغیرها را یکدست بنویسید (همیشه i یا همیشه i، نه I و i).
اگر فلوچارت خیلی طولانی شد، آن را با دایره اتصال به چند بخش بشکنید.
نکته عملی: برای کشیدن فلوچارت از ابزارهایی مثل draw.io، Lucidchart یا حتی pencil و کاغذ استفاده کنید. برای این دوره، فلوچارتها بهصورت متن و با نمادهای استاندارد ●▰▮◆▱◎ نمایش داده میشوند تا یادگیریشان آسان باشد.
اشتباهات رایج در فلوچارت
این خطاها اغلب در فلوچارت تازهکارها دیده میشود:
۱. عدم تعیین بله/خیر روی لوزی. اگر لوزی a > b؟ است، باید مشخص کنید کدام فلش «بله» است و کدام «خیر».
۲. چند کار در یک مستطیل. مثل a, b ← b, a (همزمان جابهجایی). این در الگوریتم بهدرستی تعریف نشده؛ بهجای آن از سه مستطیل جداگانه استفاده کنید.
۳. استفاده از مستطیل به جای متوازیالاضلاع برای ورودی/خروجی. این تفاوت ظاهری به نظر بیاهمیت میآید، اما در اسناد رسمی مهم است.
۴. فراموش کردن مقداردهی اولیه. در فلوچارت فاکتوریل، اگر P ← 1 را فراموش کنید، در کد مقدار P نامشخص خواهد بود.
۵. فراموش کردن گام افزایش شمارنده در حلقه. اگر در حلقه i ← i + 1 را ننویسید، حلقه بینهایت ایجاد میشود.
۶. عدم رسید به پایان. هر مسیری که از شروع شروع میشود باید به یک پایان برسد. اگر مسیری «در هوا» تمام میشود، الگوریتم شما ناقص است.
۷. بههم ریختن اولویت عملگرها در محاسبات. مثلاً P ← P*(L+W) در نسخه اصلی جزوه اشتباه بود؛ فرمول صحیح P ← 2*(L+W) است. همیشه از پرانتز استفاده کنید تا اولویت روشن باشد.
اهداف:
تعریف دقیق الگوریتم و درک چرایی نیاز به آن پیش از نوشتن کد
شناخت کامل نمادهای استاندارد فلوچارت: بیضی، مستطیل، لوزی، متوازیالاضلاع و فلش
ترسیم فلوچارت برای سه مسئله کلاسیک: جابهجایی دو مقدار، یافتن بزرگترین و حل معادله درجه یک
نکات کلیدی:
الگوریتم مجموعهای محدود، مشخص و ترتیبی از گامها برای حل مسئله است؛ قبل از کدنویسی باید طراحی شود.
فلوچارت زبان بصری بینالمللی برای نمایش الگوریتم است؛ نمادهای آن (بیضی، مستطیل، لوزی، متوازیالاضلاع، فلش) استاندارد هستند.
در لوزی تصمیم، باید هر دو فلش خروجی با «بله» و «خیر» برچسبگذاری شوند تا مسیر اجرا روشن باشد.
برای جابهجایی دو مقدار، یک متغیر کمکی لازم است؛ انتساب مستقیم `a=b; b=a;` مقدار اولیه را از بین میبرد.
نام درس، موضوع یا کلمه کلیدی را بنویسید و با Enter به آن بروید
1#include<iostream>2usingnamespace std;34main(){5int a, b, c, max;// فکر نکردهایم چطور پیدا کنیم6 cin >> a >> b >> c;7if(a > b > c)// خطای منطقی! این عبارت آنچه شما میخواهید را محاسبه نمیکند8 cout << a;// (a > b) اول ارزیابی میشود (true/false = 1/0)9// سپس نتیجه با c مقایسه میشود — نه همان a10// صحیح: a > b && b > c11elseif(b > c)12 cout << b;13else14 cout << c;15// main نوع بازگشتی ندارد، return 0 نیست16}
1// الگوریتم:2// 1. سه عدد a, b, c را از ورودی بگیر3// 2. فرض کن max = a4// 3. اگر b > max، آنگاه max = b5// 4. اگر c > max، آنگاه max = c6// 5. max را چاپ کن78#include<iostream>9usingnamespace std;1011intmain(){12int a, b, c, max;13 cin >> a >> b >> c;14 max = a;// فرض اولیه15if(b > max) max = b;16if(c > max) max = c;17 cout << max << endl;18return0;19}
a = b;b = a;
flow.svg100%
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
شروع/پایانپردازشتصمیمورودی/خروجی
1#include<iostream>2usingnamespace std;34intmain(){5int a, b, t;6 cout <<"do adad vared konid: ";7 cin >> a >> b;89// جابهجایی با متغیر کمکی10 t = a;// ذخیره موقت مقدار a11 a = b;// نوشتن مقدار b در a12 b = t;// بازیابی مقدار اولیه a در b1314 cout <<"baad az jabejaei: a = "<< a <<", b = "<< b << endl;15return0;16}
flow.svg100%
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
شروع/پایانپردازشتصمیمورودی/خروجی
1#include<iostream>2usingnamespace std;34intmain(){5int a, b, c, max;6 cout <<"se adad vared konid: ";7 cin >> a >> b >> c;89 max = a;// فرض اولیه10if(b > max){11 max = b;12}13if(c > max){14 max = c;15}1617 cout <<"bigitarin = "<< max << endl;18return0;19}
flow.svg100%
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
شروع/پایانپردازشتصمیمورودی/خروجی
1#include<iostream>2usingnamespace std;34intmain(){5double a, b, x;6 cout <<"zarib a va b ra vared konid: ";7 cin >> a >> b;89if(a !=0){10 x =-b / a;11 cout <<"rishe = "<< x << endl;12}else{13// a == 014if(b ==0){15 cout <<"bi-nahayat javab (har x javab ast)"<< endl;16}else{17 cout <<"moadele javab nadarad"<< endl;18}19}20return0;21}