درود به همه دوستان
چنگانی هستم و با آموزش جاوا، جلسه نهم در خدمتتون هستم.
این جلسه ابتدا در مورد یک ساختمان داده خیلی معروف در برنامه نویسی صحبت می کنیم. و بعد شروع میکنیم به پیاده سازی این ساختمان داده.
اسم این ساختمان داده Stack یا پشته هست. همانطور که گفته شد قبلا، منظور از ساختمان داده منظور مفهومی هست که یکسری داده را در کنار هم طبق یک روش خاص ذخیره میکنند و بازیابی میکنند.
هر ساختمان داده در جاهایی خاصی لازم میشه و یه برنامهنویس لازم هست که انواع این ساختمان دادهها را بدونه.
خوب ساختمان داده استک مفهوم خیلی خیلی سادهای داره. همیشه برای بیان مفهوم استک از یک مثال ساده استفاده میکنیم. شما فرض کنید چندتا کتاب داشته باشید.
کتاب اول رو روی میز میگذاریم. کتاب دوم رو روی کتاب اول. کتاب سوم رو هم روی کتاب دوم میگذاریم.
خوب الان اگه بخواهیم کتاب اول رو برداریم، مجبوریم که اول کتاب که در بالای همه هست (کتاب سوم) رو ابتدا برداریم و کنار بگذاریم، بعد کتاب دوم و در نهایت به کتاب اول برسیم.
در واقع این ساختمان داده شبیه یه آرایه هست که دادهای که اول میآید همیشه آخر خارج میشود و عنصری که جدید آمده است زودتر از سایرین خارج میشود!
خوب این ساختمان داده دو متد معروف داد به نامهای push و pop.
متد push یک عنصر دریافت میکند و آن را داخل ساختمان قرار داده و متد pop به نحوی که بالا گفتم عنصر را خارج میکند.
در جاوا شما میتونید به این صورت از استک استفاده کنید:
خوب الان قصد داریم خودمون این ساختمان داده رو پیدا سازی کنیم.
فرض کنید هدف ساختن یک ساختمان داده از جنس int هستیم.
پس اجازه بدین دست به کار بشیم
خوب برای پیاده سازی این ساختمان داده نیاز به یک آرایه از جنس int داریم. و همیشه باید بدونیم در هر لحظه چه تعداد عنصر داخل این آرایه هست. پس کد ما به این صورت میشه:
خوب شاید سوال براتون پیش بیاد که چرا top با مقدار اولیه -۱ مقدار دهی شده؟
جواب این سوال برمیگرده به نحوه پیاده سازی متد push و pop که پیاده سازی میکنیم. ولی در حالت کلی وقتی هیچ عنصری داخل ارایه ما نباشه مقدار top برابر است با -۱ چون ارایه ما از ۰ شروع میشن.
خوب تابع push به این صورت میشه:
public void push(int value){
top++;
array[top] = value;
}
public void push(int value){
top++;
array[top] = value;
}
که مشخصا معلوم هست برای اضافه کردن ابتدا یک واحد به top زیاد میکنیم و بعد مقدار value یا همان مقداری که قرار اضافه شود را به آرایه اضافه میکنیم.
به همین صورت متد pop:
public int pop(){
int value = array[top];
top--;
return value;
}
ابتدا مقدار خانه که top به آن اشاره میکند رو نگه داشته. top را کم میکنیم و مقدار آن رو return میکنیم.
و یک سری متد دیگه… . خروجی به این صورت میشه:
بدون اینکه اون رو حذف کنه!
متد peek شبیه pop هست با این تفاوت که همیشه اخرین عنصر رو برمیگردونه
متد isEmpty هم خالی بودن ساختمان داده رو بررسی میکند
و isFull پر بودن ساختمان داده رو
خوب برای استفاده به این صورت عمل میکنیم:
public static void main(String[] args){
MyStack theStack = new MyStack(10);
theStack.push(10);
theStack.push(20);
theStack.push(30);
theStack.push(40);
theStack.push(50);
while (!theStack.isEmpty());
long value = theStack.pop();
System.out.print(value);
System.out.print(" ");
}
System.out.println("");
}
خروجی کد هم به این صورت خواهد بود:
50 40 30 20 10
دقیقا برعکس چیزی که وارد کردیم. یعنی اولین عنصر که وارد شدهُ اخرین عنصر هست که چاپ میشود.
خوب تا اینجای بحث خیلی ساده بود و چیز خیلی خاصی گفته نشد. ولی سوالی که پیش میاد این هست که اگه ما بخواهیم یک استک از جنس String داشته باشیم چی؟ یا یک استک از جنس Student و یا از هر جنسی!!
ساده ترین راه حل این هست که به ازای هرکدوم از type های که نیاز داریم یک کلاس جدا بنویسیم!! راه حل ساده ولی بدترین روش ممکن!!!
راه حل دوم اینکه نوع آرایه استک رو از جنس Object بگیریم. خوب اینجوری هر نوع عنصری رو میشه باهم داخل آرایه ریخت. در واقع یک آرایه ساخته میشه از انواع type ها.
خوب مدیریت این نوع آرایه ها به شدت سخت هست چون هر خانه اون میتونه هر نوع دادهای باشه و همچنین نیاز به تبدیل کردن و cast کردن هستیم!! خوب پس این روش هم مناسب نیست.
چاره کار استفاده از مفهومی در جاوا هست به نام Genericها. در واقع جنریکها این قابلیت را به ما میدن که بدون در نظر گرفتن نوع type برای آن ها کلاس بسازیم. مثلا کلاس استک
خوب وقتی کلاس استک رو به صورت Generic بنوسیسم. یکبار مینویسیم و برای انواع دادهها ازش استفاده میکنیم! واقعا عالی هست مگه نه؟
البته مفهوم جنریک خیلی گسترده هست و نکات ریزی داره در استفاده ولی ما به صورت کلی صحبت میکنیم و به جزییات نمیپردازیم.
خوب قبل از شروع یک یادآوری از کلاس List بکنیم. یادتون هست چطور یک لیست در جاوا میساختیم؟
List list = new ArrayList<>();
List list = new ArrayList<>();
ما اینجا یک لیست از جنس String ساختهایم و اگه بخواهیم از جنس Integer بسازیم به این صورت:
List list = new ArrayList< > ();
شما میتونید انواع type ها رو برای این کلاس لیست بنویسید. در واقع کالکشن لیست به صورت جنریک پیادهسازی شدهاند. یعنی در واقع هر نوع دادهای رو میتونه قبول کند. فقط کافیه نوع داده خودمون رو داخل <> قرار بدیم تا لیست ما از جنس آن type بشه.
در واقع همه کالکشنها در جاوا به صورت جنریک پیاده سازی شدهاند و هرکجا علامت <> رو دیدن در واقع یاد جنریکها بیوفتین!
این این جلسه به صورت مختصر توضیح میدیم و جلسه بعدی با مثال بیشتر در موردش صحبت میکنیم. این جلسه فقط با ظاهر جنریک آشنا بشیم و توضیحاتش برای جلسه بعدی باشد.
کلاس استک ما به صورت جنریک به این صورت خواهد بود:
در اینجا ما در کنار اسم کلاس type به نام T تعریف کردیم که واقعا وجود ندارد و یک تایپ به صورت جنرال هست. یعنی هر تایپی میتونه باشه و برای ما مهم نیست.
دقت کنید نوع آرایه و ورودی و خروجی متدهای pop و push تبدیل به همین نوع T شده اند.
اجازه بدین در جلسه بعدی با جزییات بیشتری در موردش حرف بزنیم. و نحوه استفاده هم همینطور
امیدوارم این جلسه مفید بوده باشه.