استراکچر در c++

در نوشته قبل و در آموزش ساختار به بیان مفاهیم و اصول استراکچر پرداخته شد. در این نوشته در قالب دو مساله کاربردی آموزش استراکچر در c++ رو دنبال میکنیم. در هر دو مساله مثالهای مرتبط از ساده به سخت مرتب شده است.

مساله اول – دانشجویان

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

مثال 1- برنامه ای بنویسید که از ورودی اطلاعات 100 دانشجو شامل نام دانشجو، شماره دانشجو و معدل دانشجو دریافت کند و بالاترین معدل را چاپ کند.

در آموزش ساختار در مورد دریافت اطلاعات یک دانشجو صحبت کردیم و در آنجا استراکچر student را معرفی کردیم. اما در این مثال نیاز است که ما اطلاعات 100 دانشجو را از ورودی دریافت کنیم. بنابراین باید از آرایه ها استفاده کنیم. اگر به یاد داشته باشید برای تعریف یک آرایه 100 تایی از نوع int از کد زیر استفاده میکردیم:

;int A[100]

دقیقا به همین صورت می‌توان آرایه ای از استراکچر student تعریف کرد:

;student s[100]

در تصویر زیر استراکچر student را می‌بینید که شامل سه عضو داده ای number، name و avg است. ما در این مثال به آرایه ای از جنس student نیاز داریم. آرایه S آرایه ای از جنس student است و همانطور که در تصویر می‌بینید هر درایه این آرایه شامل سه عضو داده ای است.که برای دسترسی به هر کدام از اعضا مانند قبل باید از دات ( . ) استفاده کنیم. مثلا چنانچه بخواهید به نام Ali دسترسی داشته باشید باید اینگونه بنویسید: s[0].name و یا برای دسترسی به شماره دانشجویی Sina باید به این شکل دسترسی پیدا کنید: S[3].number. با توجه به اینکه شما میخواهید بالاترین معدل را پیدا کنید در واقع به یک پیمایش شبیه به نوار قرمز رنگ در تصویر زیر نیاز دارید:

استراکچر در c++

با این توضیحات به سراغ کد می‌رویم:

#include <iostream>

using namespace std;

struct student {
	int number;
	string name;
	float avg;
};

int main(){
	
	int const n=100;
	student s[n];
	
	int i,max=0;
	
	for(i=0;i<n;i++)
	{
		cout<<"Enter name of student: ";
		cin>>s[i].name;
		
		cout<<"Enter number of student: ";
		cin>>s[i].number;
		
		cout<<"Enter average of student: ";
		cin>>s[i].avg;
		
		cout<<endl<<"*********"<<endl<<endl;
	}
	
	for(i=0;i<n;i++)
		if(s[i].avg > max)
			max = s[i].avg;
			
	cout<<"max: "<<max;		
}

توضیح کد:
در خط 18 تا 30 اطلاعات دانشجویان در آرایه قرار میگیرد. آرایه s از جنس student است بنابراین هر خانه آرایه از جنس student است و شامل سه متغیر name، number و avg است. بنابراین دستور cin>>s[i] به تنهایی یک کد اشتباه است و باید مشخص کنیم که کدام عضو داده ای این اندیس قرار است دریافت شود. در خط 21، 24 و 27 اعضای داده ای s[i] دریافت می‌شوند.
دز خط 32 تا 34 کل آرایه پیمایش می‌شود و فقط عضو داده ای avg اعضا ملاقات می‌شود. دوباره تاکید میکنیم که s[i] به تنهایی بی معنی است و باید دقیق مشخص شود که به چه عضو داده ای s[i] نیاز داریم. در خط 33 با استفاده از s[i].avg به تک تک معدل دانشجویان دسترسی پیدا میکنیم و با مقایسه آن با max بزرگترین عدد را پیدا میکنیم.

تذکر: در خط 13 مقدار n را برابر 100 قرار داده ایم، شما اگر میخواهید این برنامه را تست کنید n=3 قرار دهید تا در تست برنامه نیاز به وارد کردن اطلاعات 100 دانشجو نداشته باشید! اگر از نحوه استفاده const هم اطلاعی ندارید مثال 4 آموزش آرایه را بخوانید.

در مثال بالا فقط معدل دانشجو را پیدا کردیم. در مثال بعدی همه اطلاعات دانشجویی که بیشترین معدل را دارد چاپ می‌شود.

مثال 2 – برنامه ای بنویسید که اطلاعات 100 دانشجو را از ورودی دریافت کند و نام دانشجویی که بیشترین معدل دارد را چاپ کند.

اگر به یاد داشته باشید در بحث آرایه ها به دو روش جستجوی یک عدد را انجام دادیم. یکی پیدا کردن عدد (به این معنی که آیا عدد در آرایه وجود دارد یا خیر) و دیگری پیدا کردن مکان آن عدد (به این معنی که اگر عدد در آرایه وجود دارد در چه خانه ای ذخیره شده است. (مثال 5 آموزش آرایه را ببینید) در این مثال از ایده روش دوم استفاده می‌کنیم، یعنی اگر در پیمایش آرایه متوجه شدیم که معدل از max بزرگتر است اندیس خانه آرایه را در idx ذخیره میکنیم. مثلا در تصویر زیر ما به دنبال یافتن خانه 2 آرایه هستیم. زیرا اگر شما این خانه را پیدا کنید ( که در آن بزرگترین معدل آرایه وجود دارد) به راحتی میتوانید به نام و معدل دانشجو دسترسی داشته باشید.

دانشگاه برنامه نویسان جلسه 10 - استراکچر در c++ - مثالها
یوتیوب

با این توضیحات به سراغ کد می‌رویم:

#include <iostream>

using namespace std;

struct student {
	int number;
	string name;
	float avg;
};

int main(){
	
	int const n=3;
	student s[n];
	
	int i,max=0;
	
	for(i=0;i<n;i++)
	{
		cout<<"Enter name of student: ";
		cin>>s[i].name;
		
		cout<<"Enter number of student: ";
		cin>>s[i].number;
		
		cout<<"Enter average of student: ";
		cin>>s[i].avg;
		
		cout<<endl<<"*********"<<endl<<endl;
	}
	
	int idx = 0;
	for(i=1;i<n;i++)
		if(s[i].avg > max){
			max = s[i].avg;
			idx=i;	
		}
			
	cout<<"name: "<<s[idx].name<<endl;		
	cout<<"number: "<<s[idx].number<<endl;		
	cout<<"avg: "<<s[idx].avg<<endl;		
}

توضیح کد:
همانظور که بالاتر توضیح داده شد، در خط 33 تا 37 با استفاده از اندیس i، تک تک خانه های آرایه پیمایش می‌شود و چنانچه معدل دانشجو از max بیشتر باشد علاوه بر اینکه متغیر max آپدیت می‌شود اندیس آرایه یا همان i در idx ذخیره می‌شود.
اگر مثال 5 از بحث آرایه را خوانده باشید متوجه خواهید شد که این کد را بدون استفاده از متغیر max نیز می‌توان پیاده کرد:

int idx = 0;
	for(i=1;i<n;i++)
		if(s[i].avg > s[idx].avg)
			idx=i;		

در مثال آخر از مساله دانشجویان چند

مثال سوم: برنامه ای بنویسید که از ورودی اطلاعات 100 دانشجو شامل نام، شماره دانشجویی، معدل و تاریخ تولد آنها را دریافت کند. سپس:
الف) میانگین معدل کلاس را چاپ کند.
ب) نام دانشجویانی که معدل آنها از میانگین معدل دانشجویان بیشتر است را چاپ کند.
ج) تعداد دانشجویانی که معدل زیر 14 دارند را چاپ کند.
د) نام جوانترین دانشجوی کلاس را چاپ کند.

با توجه به توضیحات کاملی که در مثال 1 و 2 دادیم انتظار داریم که موارد الف، ب و ج را بتوانید به راحتی کد نویسی کنید. برای قسمت آخر هم باید از ایده timestamp کمک بگیرید. کد 3 قسمت اول را در ادامه مشاهده میکنید

#include <iostream>

using namespace std;

struct date{
	int day,month,year;	
};

struct student {
	int number;
	string name;
	float avg;
	date d;
};



int main(){
	
	int const n=3;
	student s[n];
	
	int i,max=0;
	
	for(i=0;i<n;i++)
	{
		cout<<"Enter name of student: ";
		cin>>s[i].name;
		
		cout<<"Enter number of student: ";
		cin>>s[i].number;
		
		cout<<"Enter average of student: ";
		cin>>s[i].avg;
		
		cout<<"Enter birthday of student(day,month,year)"<<endl;
		cout<<"Day: ";
		cin>>s[i].d.day;
		cout<<"Month: ";
		cin>>s[i].d.month;
		cout<<"Year: ";
		cin>>s[i].d.year;
		
		cout<<endl<<"*********"<<endl<<endl;
	}
	
	//الف
	float sum = 0;
	float mid;
	for(i=0;i<n;i++)
		sum = sum + s[i].avg;
	
	mid=sum/n;
	cout<<"Average of avg: "<<mid<<endl	;

	cout<<endl<<"*********"<<endl<<endl;	
	//ب
	for(i=0;i<n;i++)
		if(s[i].avg>mid)
			cout<<s[i].name<<endl;
		
	
	cout<<endl<<"*********"<<endl<<endl;
	//ج
	int counter = 0;
	for(i=0;i<n;i++)
		if(s[i].avg <14)
			counter++;
	cout<<"Students with avg of less than 14: "<<counter<<endl;

       
						
}

توضیح کد:
موارد الف، ب و ج نیاز به توضیح اضافه ندارند و کدها گویا هستند. برای قسمت د هم میتوانید نمونه سوالات زیر را مشاهده کنید و در صورت تمایل حل همه سوالات را تهیه کنید:

مساله دوم – مختصات دو بعدی

در این مساله می‌خواهیم در مورد مختصات دوبعدی مثال حل کنیم. قبل از این که به مثالها برسیم کمی در مورد کاربرد جذاب این مساله صحبت کنیم. مطالبی که در ادامه مطرح می‌شود صرفا جهت بالا بردن انگیزه شما در یادگیری این مثالهاست و چنانچه این مطالب را کامل متوجه نشدید جای نگرانی نیست و میتوانید مستقیما به سراغ مثالها بروید.

OCR

OCR که مخفف عبارت Optical Character Reader است، تکنولوژی است که صفحات حاوی متنی که اسکن کرده‌اید را از فرمت عکس به متن تبدیل می‌کند. از یک مثال ساده استفاده می‌کنیم. حتما نرم افزارهایی را دیده‌اید که کارت بانکی شما را اسکن می‌کنند و شماره کارت موجود در عکس را بیرون می‌کشند. این نرم‌افزارها نمونه ساده ای از OCR ها هستند.

دانشگاه برنامه نویسان جلسه 10 - استراکچر در c++ - مثالها
تصویر 1

اما این نرم افزار ها چگونه عمل می‌کنند؟ در واقع این نرم افزارها داده هایی تحت عنوان داده های آموزشی دارند که از این داده ها برای تشخیص اعداد روی کارت استفاده می‌کنند. فرض کنید که این داده ها در نرم افزار برچسب گذاری شده اند و به ازای هر تصویر میدانیم که این تصویر چه عددی است:

دانشگاه برنامه نویسان جلسه 10 - استراکچر در c++ - مثالها
تصویر 2

حال کافیست الگوریتمی نوشته شود که ابتدا ارقام موجود در کارت به 16 تصویر (که هر کدام شامل یک رقم است) تبدیل شود و هر عکس را با عکسهای موجود در داده های آموزشی (تصویر 2) مطابقت دهد و نزدیکترین (شبیه ترین) عکس را پیدا کند. از آنجایی که داده های آموزشی برچسب گذاری شده است و میدانیم هر عکس چه عددی است به این شکل می‌توان اعداد روی کارت را شناسایی کنیم. سوالی که ممکن است در ذهن شما نقش ببندد این است که چطور میتوان نزدیکترن عکس را پیدا کرد؟ شاید اگر به این مساله بخواهید فکر کنید هیچ روشی که بتوان الگوریتم آن را نوشت و پیاده سازی کرد به ذهنتان نرسد. زیرا که داده های ورودی شما عکس است و تا به حال با این جنس مساله روبرو نشده اید. برای این کار ما نیاز به مدل بندی مساله داریم. برای این کار باید عکس را به گونه ای به آرایه تبدیل کنیم که آرایه نماد آن عکس باشد. به این معنی که بتوانیم از آن آرایه هم عکس را تولید کنیم. اینکه چه طور می‌شود عکس را به آرایه تبدیل کرد در حوصله این بحث نیست ولی همین که متوجه شدید برای کار کردن با عکس، باید عکس را به آرایه یا ماتریس مدل بندی کرد قدم بزرگی در درک برنامه ها و نرم افزارهای اطراف شماست. الان شما میدانید که اگر میخواهید دو عکس شبیه به هم را پیدا کنید در واقع باید به دو آرایه شبیه به هم را پیدا کنید. البته اگر بخواهیم دقیق تر صحبت کنیم منظور ما از آرایه مثلا 5 تایی، یک نقطه در مختصات 5 بعدی است. ساده تر بخواهیم در نظر بگیریم آرایه دوتا میشود همان نقطه ای که در صفحات دو بعدی روی کاغذ با آن کار میکنیم. در مثالهای پیش رو ما با مختصات دو بعدی کار میکنیم ولی شما می‌توانید همچنان مساله OCR را در ذهن خودتان در این مثالها دنبال کنید.

مثال 1- برنامه ای بنویسید که از ورودی دو نقطه (در مختصات دو بعدی) از ورودی دریافت کند و فاصله این دو نقطه را محاسبه کند.

در این مثال داده ورودی ما نقطه است. هر نقطه یک x دارد و یک y. بنابراین بهتر است از یک استراکچر به نام point استفاده کنیم که شامل دو عضو داده ای x و y است. پس وقتی میخواهیم دو نقطه از ورودی دریافت کنیم در واقع میخواهیم دو متغیر از جنس point از ورودی دریافت کنیم. کد زیر را ببینید:

#include <iostream>
#include <cmath>

using namespace std;

struct point {
	double x,y;
};

int main(){
	point p1,p2;
	
	cout<<"Enter point1 (x,y): "<<endl;
	
	cout<<"X: ";
	cin>>p1.x;
	
	cout<<"Y: ";
	cin>>p1.y;

	cout<<"Enter point2 (x,y): "<<endl;
	
	cout<<"X: ";
	cin>>p2.x;
	
	cout<<"Y: ";
	cin>>p2.y;


	double d = sqrt(pow(p1.x - p2.x,2) + pow(p1.y - p2.y,2));
	cout<<"distance between 2 points: "<< d;
}

توضیح کد:
در خط 6 تا 8 استراکچر point تعریف شده است، در خط 13 تا 27 دو نقطه از ورودی دریافت شده است و در خط 30 فاصله دو نقطه چاپ شده است. همانطور که در آموزشهای قبل هم گفته شده است تابع sqr(x) جذر x و تابع pow(a,b) مقدار a به توان b را محاسبه میکند که پارامترهای ورودی این دو تابع حتما باید double باشند ( به همین دلیل است که در استراکچر point متغیرهای x و y را از double تعریف کردیم.
تذکر: همانطور که میدانید فاصله دو نقطه از فرمول زیر محاسبه می‌شود:

دانشگاه برنامه نویسان جلسه 10 - استراکچر در c++ - مثالها

مثال 2- برنامه ای بنویسید که از ورودی 100 نقطه دریافت کند و مرکز این نقاط را پیدا کند.

در تصویر زیر تعدادی نقاط سبز رنگ میبینید که دایره مشکی رنگ میانگی همه نقاط است. میانگین نقاط، نقطه ای است که مقدار x آن میانگین همه xها و y آن میانگین همه yهاست.

دانشگاه برنامه نویسان جلسه 10 - استراکچر در c++ - مثالها

نوشتن این کد چندان سخت نیست:

#include <iostream>
#include <cmath>

using namespace std;

struct point {
	double x,y;
};

int main(){
	
	int const n=100;
	point points[n];
	int i;
	double sum_x=0,sum_y=0;
	
	for(i=0;i<n;i++){
			
		cout<<"Enter point (x,y): "<<endl;
		
		cout<<"X: ";
		cin>>points[i].x;
		
		cout<<"Y: ";
		cin>>points[i].y;
	}
	
	for(i=0;i<n;i++){
		sum_x = sum_x + points[i].x;
		sum_y = sum_y + points[i].y;
	}
	
	cout<<"mid: ( "<<sum_x/n<<" , "<<sum_y/n<<" )"<<endl;
	
}

مثال 3- برنامه ای بنویسید که از ورودی 100 نقطه دریافت کند. سپس نقطه 101 ام را دریافت کند و نزدیکترین نقطه (از بین 100 نقطه) به نقطه جدید را پیدا کند

این مثال شبیه به صورت مساله ای است که در OCR مطرح کردیم. یعنی 100 داده آموزشی داریم و میخواهیم با استفاده از این 100 داده ، تکلیف داده 101ام را مشخص کنید!

اگر دوست دارید کد این سوال رو ببینید میتونید حل سوالات برنامه نویسی پیشرفته و یا دوره کامل آموزش سی پلاس پلاس رو تهیه کنید:

اگر در توضیح مثالهای این آموزش مشکل دارید، حتما در قسمت نظرات سوال خود را مطرح کنید.