মডিউল ৭-০ঃ সূচনা
এই মডিউলে আমরা কি কি শিখবোঃ
এরে অফ অবজেক্টস দেখব
এরে অফ অবজেক্টস থেকে মিনিমাম এবং ম্যাক্সিমাম বের করা দেখব
এরে অফ অবজেক্টস সর্ট করা শিখব
কাস্টম সর্ট দেখব
মডিউল ৭-১ঃ এরে অফ অবজেক্টস
আমরা ক্লাস এবং অবজেক্টস দেখেছি। আমাদের প্রয়োজন মতো আমরা অবজেক্টস নিয়ে কাজ করেছি। এবার আমাদের যদি কখনো অনেকগুলো অবজেক্ট এর প্রয়োজন হয়। তখন আমরা চাইলে অবজেক্টের এরে তৈরি করে ফেলতে পারি। মনে করি একটি ক্লাসে ১০০ জন স্টুডেন্ট আছে। সেই ১০০ জন স্টুডেন্টের সবার নাম, রোল এবং মার্কস স্টোর করতে হবে। তাহলে আমরা নাম, রোল এবং মার্কস নিয়ে একটি ক্লাস ডিক্লেয়ার করে ফেলতে পারি। তারপর সেই ক্লাসের ১০০ জন স্টুডেন্টের জন্য ১০০ টি অবজেক্ট ক্রিয়েট করে ফেলতে পারি। এখন এই ১০০ টি অবজেক্ট যদি আমরা আলাদা আলাদা ডিক্লেয়ার করতে চাই তাহলে অনেক সময় লাগবে। এটা না করে আমরা এক লাইনে করে ফেলতে পারি। আমরা অবজেক্টের একটা এরে নিয়ে ফেলতে পারি ১০০ সাইজের।
অবজেক্টের এরে নরমাল এরের মতোই কাজ করে। নরমাল এরের মতোই ইন্ডেক্সিং, ইনপুট, আউটপুট।
অবজেক্টের এরে ডিক্লেয়ার করার সিন্টেক্সঃ
class_name array_name [size];
#include <bits/stdc++.h>
using namespace std;
class Student // স্টুডেন্ট এর নাম, রোল এবং মার্ক্স নিয়ে একটি ক্লাস ডিক্লেয়ার করা হয়েছে।
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n; // এরে সাইজ ইনপুট নেওয়া হচ্ছে।
Student a[n]; // সেই সাইজের এরে ডিক্লেয়ার করা হচ্ছে যার ডাটা টাইপ হচ্ছে Student। কারন আমরা Student ক্লাসের অবজেক্টের এরে তৈরি করছি।
for (int i = 0; i < n; i++) // লুপ চালিয়ে প্রতিটি অবজেক্টের জন্য নাম, রোল এবং মার্ক্স ইনপুট নেওয়া হচ্ছে।
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
for (int i = 0; i < n; i++) // লুপ চালিয়ে প্রতিটি অবজেক্টের নাম, রোল এবং মার্ক্স প্রিন্ট করা হচ্ছে।
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}কোডটি রান করে আমাদের যতগুলো স্টুডেন্ট প্রয়োজন ততগুলো স্টুডেন্টদ এর ডেটা স্টোর করতে পারব। আমরা যদি চাই স্টুডেন্ট এর নামের মধ্যে স্পেস সহ স্টোর করতে, তাহলে আমাদের অল্প একটু চেঞ্জ করতে হবে। নাম ইনপুট নেওয়ার ক্ষেত্রে cin ব্যাবহার না করে getline ব্যাবহার করতে হবে। এবং প্রতিবার নাম ইনপুট নেওয়ার আগে ignore() অথবা getchar() ব্যাবহার করত হবে। নাহলে পূর্বের লাইনের শেষে দেওয়া এন্টার টা নাম হিসেবে ইনপুট নিয়ে নিবে।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin.ignore(); // প্রতিবার নাম ইনপুট নেওয়ার আগে cin.ignore() অথবা getchar() ব্যাবহার করত হবে। নাহলে পূর্বের লাইনের শেষে দেওয়া এন্টার টা নাম হিসেবে ইনপুট নিয়ে নিবে।
getline(cin, a[i].name); // getline ব্যাবহার করে স্পেস সহ নাম ইনপুট নেওয়া হচ্ছে।
cin >> a[i].roll >> a[i].marks;
}
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}আমরা চাইলে এরেটি ডায়নামিক ভাবেও নিতে পারি। একটি int এরে আমরা যেরকম ডায়নামিক নিতাম ঠিক তেমনি।
// Student a[n];
Student *a = new Student[n]; // ডায়নামিক এরে অফ অবজেক্টসমডিউল ৭-২ঃ এরে থেকে মিন এবং ম্যাক্স অবজেক্ট বের করা
এবার আমরা দেখব কিভাবে এরে অফ অবজেক্টস থেকে মিনিমাম এবং ম্যাক্সিমাম অবজেক্ট বের করতে পারি。
আমরা এরে থেকে যেভাবে মিনিমাম এবং ম্যাক্সিমাম ভ্যালু বের করতে পারতাম। ঠিক একইভাবে আমরা এরে অফ অবজেক্ট থেকেও মিনিমাম ভেলুর অবজেক্টটি বের করে ফেলতে পারি। পূর্বের আর্টিকেলে আমরা যেই ক্লাসটি দেখেছি সেখান থেকে আমরা মিনিমাম মার্ক্স পেয়েছে যেই স্টুডেন্ট তাকে যদি বের করতে চাই অর্থাৎ সেই স্টুডেন্টের অবজেক্টটি যদি বের করতে চাই তাহলে আমরা এইভাবে করে ফেলতে পারি।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n; // এরে সাইজ ইনপুট নিচ্ছি।
Student a[n]; // ইনপুট নেওয়া সাইজের এরে ডিক্লেয়ার করা হচ্ছে।
for (int i = 0; i < n; i++) // অবজেক্ট ইনপুট নেওয়া হচ্ছে।
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
Student mn; // মিনিমাম অবজেক্টটি বের করে স্টোর করার জন্য একটি অবজেক্ট নেওয়া হয়েছে।
mn.marks = INT_MAX; // যেহেতু আমরা মার্ক্স দেখে মিনিমাম বের করব তাই এই অবজেক্ট এর মার্ক্স শুরুতে INT_MAX দিয়ে ইনিশিয়ালাইজ করা হয়েছে।
for (int i = 0; i < n; i++) // তারপর নরমালি আমরা এরে থেকে মিনিমাম বের করার জন্য যেভাবে লুপ চালাতাম সেভাবে লুপ চালিয়ে এরের শুরু থেকে শেষ পর্যন্ত সবগুলো অবজেক্ট এর কাছে যাওয়া হচ্ছে।
{
if (a[i].marks < mn.marks) // অবজেক্টের মার্ক্স এর সাথে আমাদের আন্সার অবজেক্ট এর মার্ক্স কম্পেয়ার করে দেখা হচ্ছে। যদি অবজেক্টের মার্ক্স কম হয় তাহলে আমাদের আন্সার অবজেক্ট অর্থাৎ মিনিমাম অবজেক্ট আপডেট করা হচ্ছে।
{
mn = a[i]; // আন্সার অবজেক্ট অর্থাৎ মিনিমাম অবজেক্ট এর মধ্যে লুপের অবজেক্টকে রেখে দেওয়া হচ্ছে কারন এই অবজেক্ট এর মার্ক্স আমাদের মিনিমাম অবজেক্ট থেকে কম। এভাবে লুপ শেষে সবচেয়ে কম মার্ক্স এর অবজেক্টটি অর্থাৎ স্টুডেন্টটির ডাটা স্টোর থাকবে mn অবজেক্টটিতে।
}
}
cout << mn.name << " " << mn.roll << " " << mn.marks << endl; // মিনিমাম অবজেক্ট প্রিন্ট করা হচ্ছে।
return 0;
}কোডটি রান করে কিছু স্টুডেন্ট ইনপুট দিলে সবথেকে কম মার্ক্স পাওয়া স্টুডেন্ট প্রিন্ট হয়ে যাবে। আমরা চাইলে সেইম লজিকে ম্যাক্সিমাম অবজেক্টটিও প্রিন্ট করতে পারি।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
Student mx; // ম্যাক্সিমাম অবজেক্টটি বের করে স্টোর করার জন্য একটি অবজেক্ট নেওয়া হয়েছে।
mx.marks = INT_MIN; // যেহেতু আমরা মার্ক্স দেখে ম্যাক্সিমাম বের করব তাই এই অবজেক্ট এর মার্ক্স শুরুতে INT_MIN দিয়ে ইনিশিয়ালাইজ করা হয়েছে।
for (int i = 0; i < n; i++) // তারপর নরমালি আমরা এরে থেকে মিনিমাম বের করার জন্য যেভাবে লুপ চালাতাম সেভাবে লুপ চালিয়ে এরের শুরু থেকে শেষ পর্যন্ত সবগুলো অবজেক্ট এর কাছে যাওয়া হচ্ছে।
{
if (a[i].marks > mx.marks) // অবজেক্টের মার্ক্স এর সাথে আমাদের আন্সার অবজেক্ট এর মার্ক্স কম্পেয়ার করে দেখা হচ্ছে। যদি অবজেক্টের মার্ক্স বেশি হয় তাহলে এটিই আমাদের ম্যাক্সিমাম অবজেক্ট। তাই ম্যাক্সিমাম অবজেক্ট আপডেট করা হচ্ছে।
{
mx = a[i]; // ম্যাক্সিমাম অবজেক্ট আপডেট করা হচ্ছে।
}
}
cout << mx.name << " " << mx.roll << " " << mx.marks << endl; // ম্যাক্সিমাম অবজেক্ট প্রিন্ট করা হচ্ছে।
return 0;
}কোডটি রান করে কিছু স্টুডেন্ট ইনপুট দিলে সবথেকে বেশি মার্ক্স পাওয়া স্টুডেন্ট প্রিন্ট হয়ে যাবে।
মডিউল ৭-৩, ৭-৪ঃ এরে অফ অবজেক্টস সর্ট করা সিলেকশন সর্ট দিয়ে
এবার আমরা সিলেকশন সর্ট ব্যাবহার করে এরে অফ অবজেক্টস সর্ট করব।
সিলেকশন সর্ট দিয়ে আমরা একটি ইন্টিজার এরে যেভাবে সর্ট করতাম ঠিক তেমনি একটি এরে অফ অবজেক্টসও সর্ট করে ফেলতে পারি।
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i] > a[j])
{
swap(a[i], a[j]);
}
}
}আমরা এভাবে একটি ইন্টিজার এরে সর্ট করতাম। এখানে শুধুমাত্র একটি লাইনে চেঞ্জ আসবে। if (a[i] > a[j]) দিয়ে আমরা চেক করতাম বাম পাশের ভেলুটি বড় কিনা। এরে অফ অবজেক্টস এর ক্ষেত্রে আমরা এভাবে লিখব if (a[i].marks > a[j].marks) কারন এখানে a[i] একটি অবজেক্ট, সেই অবজেক্ট এর মার্ক্স এর উপর আমরা সর্ট করছি। তাই a[i].marks কে চেক করতে হবে।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks; // এরে এলিমেন্ট ইনপুট নেওয়া হচ্ছে।
}
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i].marks > a[j].marks) // যদি বাম পাশের অবজেক্টের মার্ক্স ডান পাশের অবজেক্টের মার্ক্স এর থেকে বড় হয়ে যায়, তাহলে আমাদের সোয়াপ করতে হবে।
{
swap(a[i], a[j]); // বিল্ট-ইন সোয়াপ ফাংশন ব্যাবহার করে সোয়াপ করছি।
}
}
}
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl; // সর্টেড এরে প্রিন্ট করা হচ্ছে।
}
return 0;
}কোডটি রান করলে সর্টেড এরে অফ অবজেক্টস প্রিন্ট হবে। আমরা চাইলে বড় থেকে ছোট অর্ডারে সর্ট করে ফেলতে পারি, শুধু চিহ্নটি উল্টিয়ে দিলেই হবে। if (a[i].marks < a[j].marks)
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i].marks < a[j].marks) // আমরা চেক করছি বাম পাশের মার্ক্সটি ছোট কিনা। যেহেতু বড় থেকে ছোট সর্ট করছি তাই বাম পাশে বড় ভেলু থাকতে হবে, তাই বাম পাশের মার্ক্সটি ছোট হলে সোয়াপ করছি।
{
swap(a[i], a[j]);
}
}
}
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}এখানে আমরা চাইলে নতুন কন্ডিশন এড করেও করতে পারি। আমরা যদি এমন চাই মার্ক্স ছোট থেকে বড় সর্ট করব কিন্তু যদি মার্ক্স সমান হয় তাহলে রোল যার ছোট তাকে আগে রাখব যেমনটা আপনাদের মিড টার্ম এক্সামে ছিল। সেটাও করতে পারব আমরা। শুধু একটি কন্ডিশন এড করতে হবে।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (a[i].marks > a[j].marks)
{
swap(a[i], a[j]);
}
if (a[i].marks == a[j].marks) // যদি দুটি অবজেক্ট এর মার্ক্স সমান হয় তখন আমরা রোল এর উপর সর্ট করব।
{
if (a[i].roll > a[j].roll) // সেইমভাবে কন্ডিশন দিয়ে রোল এর উপর ভিত্তি করে সর্ট করা হচ্ছে।
{
swap(a[i], a[j]);
}
}
}
}
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}মডিউল ৭-৫ঃ এরে অফ অবজেক্টস সর্ট করা বিল্ট-ইন সর্ট ফাংশন দিয়ে
এবার আমরা বিল্ট-ইন সর্ট ফাংশন দিয়ে এরে অফ অবজেক্টস সর্ট করব।
যেহেতু এখানে আমরা একটি ক্লাসের অবজেক্ট নিয়ে কাজ করছি তাই এখানে আমরা নরমালি সর্ট ফাংশন ব্যাবহার করতে পারব না। কারন ক্লাস একটি ইউজার ডিফাইন্ড ডাটা টাইপ। ক্লাসের ডাটা টাইপ গুলো কিভাবে কাজ করে তা সর্ট ফাংশন জানবে না। তাই এখানে আমাদের আলাদাভাবে বলে দিতে হয় আমরা কিসের ভিত্তিতে সর্ট করতে চাচ্ছি।
আমরা সর্ট ফাংশনের ভেতর একটি কাস্টম কম্পেয়ার ফাংশন কে কল করি। তারপর সেই কম্পেয়ার ফাংশনে আমরা লিখি যে আমরা কিসের ভিত্তিতে সর্ট করতে চাচ্ছি। এই কম্পেয়ার ফাংশনটি হয় বুলিয়ান টাইপের এই ফাংশনটি ট্রু অথবা ফলস রিটার্ন করে। এই কম্পেয়ার ফাংশন দুটি ভ্যালু প্যারামিটার হিসেবে নেয়। তারপর সেই দুটি ভ্যালু চেক করে ট্রু অথবা ফলস রিটার্ন করে। ট্রু রিটার্ন করলে সর্ট ফাংশন বুঝে নেয় যে ঠিক আছে সর্ট করতে হবে না। আর ফলস রিটার্ন করলে সর্ট ফাংশন বুঝে নেয় যে এখানে সর্ট করতে হবে।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
bool cmp(Student a, Student b) // কাস্টম কম্পেয়ার ফাংশন যা বুলিয়ান টাইপের এবং প্যারামিটার হিসেবে দুটি অবজেক্ট নিবে।
{
if (a.marks <= b.marks) // যদি প্রথম অবজেক্টের মার্ক্স ছোট অথবা সমান হয় তাহলে অর্ডার ঠিক আছে, এখানে সর্ট করার প্রয়োজন নেই। যেহেতু আমরা ছোট থেকে বড় সর্ট করছি।
return true; // এখানে সর্ট করার প্রয়োজন নেই, তাই ট্রু রিটার্ন করা হচ্ছে।
else // নাহলে সর্ট করতে হবে।
return false; // তাই ফলস রিটার্ন করা হচ্ছে।
}
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
sort(a, a + n, cmp); // সর্ট ফাংশনকে কল করে এরে এবং কম্পেয়ার ফাংশনকে দিয়ে দেওয়া হচ্ছে।
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}আমরা চাইলে বড় থেকে ছোট অর্ডারেও সর্ট করে ফেলতে পারি। শুধু কম্পেয়ার ফাংশনে কন্ডিশন এর চিহ্নটি উল্টিয়ে দিলে হয়ে যাবে। if (a.marks >= b.marks)
পূর্বের আর্টিকেল এর মতো আমরা চাইলে মার্ক্স যদি সমান থাকে তখন রোল দিয়েও সর্ট করে ফেলতে পারব।
#include <bits/stdc++.h>
using namespace std;
class Student
{
public:
string name;
int roll;
int marks;
};
bool cmp(Student a, Student b)
{
if (a.marks < b.marks) // যদি প্রথম অবজেক্টের মার্ক্স ছোট হয় তাহলে অর্ডার ঠিক আছে, এখানে সর্ট করার প্রয়োজন নেই। যেহেতু আমরা ছোট থেকে বড় সর্ট করছি।
return true; // এখানে সর্ট করার প্রয়োজন নেই, তাই ট্রু রিটার্ন করা হচ্ছে।
else if(a.marks > b.marks) // যদি প্রথম অবজেক্টের মার্ক্স বড় হয় তাহলে অর্ডার ঠিক নেই, এখানে সর্ট করতে হবে।
return false; // সর্ট করতে হবে, তাই ফলস রিটার্ন করা হচ্ছে।
else // আর যদি প্রথম এবং দ্বিতীয় অবজেক্ট এর মার্ক্স সমান হয়, তাহলে আমাদের রোল চেক করে দেখতে হবে।
{
if (a.roll < b.roll) // যদি প্রথম অবজেক্টের রোল ছোট হয় তাহলে অর্ডার ঠিক আছে, এখানে সর্ট করার প্রয়োজন নেই। যেহেতু আমরা ছোট থেকে বড় সর্ট করছি।
return true; // এখানে সর্ট করার প্রয়োজন নেই, তাই ট্রু রিটার্ন করা হচ্ছে।
else // নাহলে সর্ট করতে হবে।
return false; // তাই ফলস রিটার্ন করা হচ্ছে।
}
}
int main()
{
int n;
cin >> n;
Student a[n];
for (int i = 0; i < n; i++)
{
cin >> a[i].name >> a[i].roll >> a[i].marks;
}
sort(a, a + n, cmp);
for (int i = 0; i < n; i++)
{
cout << a[i].name << " " << a[i].roll << " " << a[i].marks << endl;
}
return 0;
}মডিউল ৭-৬ঃ কাউন্টিং সর্ট
আজকে আমরা নতুন একটি সর্টিং এলগরিদম দেখব আর তা হলো কাউন্টিং সর্ট।
কাউন্টিং সর্ট নামটি নতুন মনে হলেও এটি আসলে নতুন না আমাদের কাছে। এটি মূলত কাজ করে ফ্রিকোয়েন্সি এরের সাহায্যে। ধরে নেই আমাদের কাছে একটি স্ট্রিং আছে "hello"। আমরা যদি ফ্রিকোয়েন্সি এরে দিয়ে স্ট্রিং এর ক্যারেক্টার কাউন্ট করি, তাহলে পাব
e = 1
h = 1
l = 2
o = 1
এখন আমরা যদি সিরিয়ালি এগুলি প্রিন্ট করে যাই ফ্রিকোয়েন্সি অনুযায়ী অর্থাৎ ১টি e, ১টি h, ২টি l, ১টি o তাহলেই আমাদের স্ট্রিংটি সর্ট হয়ে যাবে। এটিই কাউন্টিং সর্ট।
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin >> s; // স্ট্রিং ইনপুট নেওয়া হচ্ছে।
int frq[26] = {0}; // ফ্রিকোয়েন্সি এরে ডিক্লেয়ার করা হয়েছে ২৬ সাইজের কারন আমরা a থেকে z পর্যন্ত কাউন্ট করব। সবগুলো ভেলু শুরুতে ০ দিয়ে ইনিশিয়ালাইজ করা হয়েছে।
for (char c : s) // স্ট্রিং এর উপর লুপ চালিয়ে প্রতিটি ক্যারেক্টার নিয়ে আসা হচ্ছে।
{
frq[c - 'a']++; // ফ্রিকোয়েন্সি এরেতে সেই ক্যারেক্টার এর ইন্ডেক্সে যেয়ে তার কাউন্ট এর মান ১ বাড়িয়ে দেওয়া হচ্ছে।
}
for (char i = 'a'; i <= 'z'; i++) // a থেকে z পর্যন্ত লুপ চালানো হচ্ছে।
{
for (int j = 0; j < frq[i - 'a']; j++) // ফ্রিকোয়েন্সি এরেতে সেই ইন্ডেক্সে যেয়ে তার কাউন্ট এর ভেলু পর্যন্ত লুপ চালানো হচ্ছে।
{
cout << i; // ক্যারেক্টার প্রিন্ট করা হচ্ছে।
}
}
return 0;
}কোডটি রান করে কোন স্ট্রিং ইনপুট দিলে সর্টেড স্ট্রিং প্রিন্ট হবে।
