Saturday, June 28, 2014

C++ STL :: pair

কিছু কথাঃ

যারাই কিনা সি/সি++ নিয়ে বেশকিছুদিন নাড়াচাড়া করছেন, তারা প্রায় সবাই সি এর একটা দারুন জিনিস স্ট্রাকচার-এর সাথে পরিচিত, আর, আরেকটু অ্যাডভান্সডরা তো মনে হয় অলরেডি সি++ এর ক্লাস নামের জিনিসটা মোয়া বানিয়ে ফেলেছে।
সি একটা ফাটাফাটি ল্যাঙ্গুয়েজ আর সি++ এর কথা তো বলাই বাহুল্য। যারা অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এর সুবাতাস পেয়েছেন তারা এটা আরো ভাল করে জানেন। আমরা জানি, সি++ এ কিছু প্রিমিটিভ ডাটা টাইপ ডিফাইন করা আছে, যাদের উপরে আমরা খুব সহজেই বিভিন্ন অপারেশন চালাতে পারি, কিন্তু মাঝে মাঝে এই রকমের ডাটা টাইপের ব্যবহার আমাদের কে ঝামেলায় ফেলতে পারে। যেমন, মনে করা যাক আমাকে একটা 2D গ্রিডের কিছু পয়েন্ট স্টোর করতে হবে। শুধু int টাইপের অ্যারে দিয়ে এটা মেইনটেইন করাটা বেশ মুশকিলের ব্যাপার। কিন্তু যদি এরকম একটা ডাটা টাইপ থাকতো ‘point’ নামে, যা কিনা (x, y) আকারে কো-অর্ডিনেট রাখতে পারতো!!! সি এ সেই ব্যাবস্থা করেই দেয়া আছে, যেন প্রোগ্রামাররা চাইলেই ইচ্ছা মতো ডাটা টাইপ বানিয়ে নিতে পারেন, আর সি++ এটাকে আরেক ডিগ্রি এগিয়ে নিয়ে গেছে। এখানে প্রোগ্রামার চাইলে তার বানানো ডাটা টাইপের আচার আচরণও বলে দিতে পারেন।
কিন্তু, প্রশ্ন হল, এটা কন্টেস্ট প্রোগ্রামিং এর জন্য কতটা সুইটেবল?

পেয়ার কি?

কন্টেস্ট প্রোগ্রামিং-এ সাধারনতঃ খুব কমপ্লেক্স ডাটা টাইপ বানাতে হয় না। সেখানে বেশি প্রয়োজন খুব দ্রুত আর নির্ভুল কোডিং। যেমন, প্রায়ই দেখা যায়, একটা গ্রাফের এজ গুলো স্টোর করতে হবে, বা জিয়োমেট্রির প্রবলেমের জন্য কো-অর্ডিনেট নিয়ে কাজ করতে হবে, কখনো বা দেখা যায় কিছু স্ট্রিং-এর জন্য কিছু নাম্বার দিতে হবে, অথবা একগাদা ডাটা বিভিন্ন ক্রাইটেরিয়ার ভিত্তিতে সর্ট বা সার্চ করতে হবে। সাধরনতঃ এসব ক্ষেত্রে প্রোগ্রামার যদি নিজে থেকে ডাটাটাইপ বানাতে যায়, কোন সন্দেহ নাই তাতে তার মূল্যবান কিছু সময় নষ্ট হবে। যেমন, নিচের প্রবলেমটা দেখিঃ
আমাকে একগাদা 2D পয়েন্ট থাকবে, আমাকে সেগুলা সর্ট করতে হবে। এখন, আমি চাইলেই একটা স্ট্রাকচার বানাতে পারিঃ

structpoint { int x, y; } P[128];
অর্থাৎ, P[] হল একটা পয়েন্ট টাইপের অ্যারে, এখন এটাকে সর্ট করতে হবে। কাজ তো সোজাই, অ্যালগোরিদমের হেডারটা ইনক্লুড করে sort() মেরে দিলেই হয়… কিন্তু আসলে এটা এত সিম্পল না, কারন, sort() একটা টেমপ্লেট ফাংশন, মানে যে কোন ডাটাটাইপের জন্য কাজ করবে, কিন্তু তার আগে তাকে ডাটাটাইপের ভাবগতি জানাতে হবে। আমি ‘struct point’ দিয়ে কি বুঝাতে চাই, এটা তার বুঝার কোন কারনই নাই যদি না আমি বলে দেই। তার মানে খালি sort() কে ডাকলেই চলবে না, তার সাথে অপারেটর ওভারলোড বা কম্পেয়ার ফাংশন লিখে বুঝিয়ে দিতে হবে যে আমি আসলে কি চাই। আর এখানেই std::pair এর প্লাস পয়েন্ট।
std::pair জিনিশটা তেমন কিছুই না, জাস্ট দুইটা ভ্যালু কে একসাথে করে রাখে, যেখানে ভ্যালু দুইটা যে কোন টাইপের হতে পারে, ডিফারেন্ট টাইপেরও হতে পারে। পেয়ার ক্লাসটা ডিফাইন করা থাকে std <utility> নামের হেডারে।
#include <utility>
using namespace std;
pair ক্লাসের ডেফিনিশনঃ
template <class T1, class T2> struct pair {
    T1 first;
    T2 second;
    pair(): first(T1()), second(T2()) {}
    pair(const T1 &x, const T2 &y): first(x), second(y) {}
    template <class U, class V> pair(const pair<U, V> &p): first(p.first), second(p.second) {}
};
যাদের টেমপ্লেট সম্পর্কে আইডিয়া নাই, তাদের জন্য অল্প কথায়, টেমপ্লেট একটা সিস্টেম যেখানে কোন অ্যাকচুয়াল টাইপের জন্য ডিজাইন থাকে না, বরং যে কোন টাইপের জন্য তার একটা ইন্সট্যান্স তৈরি করা যায়। টেমপ্লেট শিখতে হলেএই পেজটি দেখা যেতে পারে।
pair এর সুবিধা হল, এটা টেমপ্লেট টাইপ, তাই STL algorithm এর ফাংশন গুলার জন্য সাধারনতঃ pair অবজেক্ট গুলার আলাদা করে কোন পরিচয় দেওয়ার দরকার পড়ে না। যেমন আগের প্রবলেমে জাস্ট sort() কল দিলেই চলে, সে অটমেটিক প্রথমে পেয়ারের প্রথম মেম্বার, তার পর ২য় টা, তার পর ৩য় টা, এভাবে বাকি গুলা কম্পেয়ার করে দেখবে। প্রোগ্রামারকে এর জন্য কিছুই বলতে হবে না।

কিভাবে ব্যবহার করে?

pair নিয়ে কাজ করতে চাইলে <utility> হেডার ইনক্লুড করা উচিৎ, অবশ্য যে কোন STL হেডার ইনক্লুড করলেই pair ব্যবহারের সুবিধা পাওয়া যায়। আর pair টাইপের অবজেক্ট সহজে ক্রিয়েট করার জন্য <utility> হেডারের make_pair() ফাংশন ব্যবহার করা যায়। আর pair-এর ১ম আর ২য় এলিমেন্টকে যথাক্রমে .first আর .second মেম্বার দিয়ে অ্যাক্সেস করা যায়। নিচে একটা উদাহরন দেখানো হলঃ
#include <iostream>
#include <string>
#include <utility>
using namespace std;
int main() {
    // simple constructions
    pair< int, int > px, py;
    pair< int, int > p1(23, 43);
    pair< int, int > p2 = pair< int, int >(234, 534);
    px = p1;
    py.first = p2.first * px.second, py.second = p2.second * px.first;
    cout << "py: (" << py.first << ", " << py.second << ")\n";
    
    // bit more complex
    pair< pair< int, int >, pair< int, int > > p3;
    p3 = pair< pair<int, int>, pair< int, int > > (px, py);
    cout << "p3: ((";
    cout << p3.first.first << ", " << p3.first.second << "), (";
    cout << p3.second.first << ", " << p3.second.second << "))\n";
    
    // using make_pair()
    pair< double, pair< string, int > > p4;
    p4 = make_pair(3.14159, make_pair("pi", 5) );
    cout << "this is " << p4.second.first << ", value: " << p4.first;
    cout << " precision: " << p4.second.second << " digits\n";
    return 0;
}
pair নিয়ে সবচেয়ে বেশি যে কথাটা শোনা যায় তা হল, মানুষজন নাকি .first.second.second.first…. এরকম চেইন লিখতে লিখতে টায়ার্ড হয়ে যায়। কিন্তু একটু কাজ করেই এইটাকে সহজ করে ফেলা যায়, যেমন, নিচের কোডে pair কে #define করে নেওয়া হয়েছেঃ
#include <iostream>
using namespace std;
#define pii pair< int, int >
#define ppi pair< pii, int >
#define ff first
#define ss second
int main() {
    ppi p1;
    pii p2;
    cin >> p2.ff >> p2.ss;
    p1 = ppi( p2, p2.ss * p2.ff );
    cout << "entry: " << p1.ff.ff << ", " << p1.ff.ss << endl;
    cout << "product: " << p1.ss << endl;
    return 0;
}
অন্যান্য STL কন্টেইনারের ডাটা টাইপ হিসাবেও pair ব্যবহার করা যায়। যেমন, বি.এফ.এস. অ্যালগরিদমে প্রায়ই কিউতে একজোড়া নাম্বার রাখতে হতে পারে, অথবা ডায়াকস্ট্রার অ্যালগরিদমে পুরা একটা এজকে প্রাইওরিটি কিউতে রাখার ব্যাবস্থা করতে হয়। এটাও খুব সহজেই করা যায়ঃ
#include <queue>
using namespace std;
#define pii pair< int, int >
#define edge pair< int, pii >
// edge.first is weight, edge.second is a pair indicating endpoints
queue< pii > Q;
priority_queue< edge, vector< edge >, greater< edge > > PQ;

সতর্কতাঃ

অন্যান্য সব STL অবজেক্টের মত, এখানেও একটা ব্যাপার খেয়াল করতে হবে তা হলঃ উপরের উদাহরন গুলাতে দেখা যায় কন্সট্রাকশন শেষ করার সময় মাঝে মাঝে পর পর দুইটা > ব্যবহার করতে হয়, (যেমন প্রাইওরিটি কিউ এর উদাহরনে শেষে ……greater< edge > >, এখানে শেষ ২টা > এর মাঝখানে একটা স্পেস ব্যবহার করা হয়েছে, এটা কিন্তু সৌন্দর্য বর্ধনের জন্য না। এটা না দিলে অনেক সময় কম্পাইলারের মাথা গরম হয়ে যায়। কারন সি++ এ >> আরো কয়েকটা অপারেটরের কাজ করে। আর যেসব যায়গায় দেখা যায় pair ইউজ করলে আরো ঝামেলা হয়, সেখানে নরমাল স্ট্রাকচার ব্যবহার করাটাই বেশি ভাল। এটা জেনে রাখা ভাল, আর জানলেই যে বসাতে হবে এমনও কোন কথা নাই।

ব্যবহারঃ

সাধারনতঃ STL এর টেমপ্লেট ক্লাসগুলোর ওভারলোডিং সুবিধা নেওয়ার জন্য এবং ছোটো খাটো স্ট্রাকচারের শর্টহ্যান্ড হিসাবে pair ব্যবহার করা হয়ে থাকে। এছাড়া std::map এ হাশিং এর সময় pair ব্যবহার করা হয়। প্রোগ্রামিং প্রবলেমগুলাতে গ্রাফ আর জিওমেট্রিক রিপ্রেজেন্টেশনে pair অনেক ব্যবহার করা হয়।

সি++ এর প্রাথমিক ধারণা

আমরা যারা কন্টেস্ট প্রোগ্রামার, আমরা যতটা না একজন প্রোগ্রামার তার চে’ অনেক বেশি হচ্ছি একজন প্রবলেম সলভার। আমরা কিন্তু ঠিক প্রথাগত কম্পিউটার সায়েন্টিস্ট ও নই, যারা মোটামুটি একটা কঠিন প্রবলেম পৃথিবীর কোণাকান্চি থেকে খুঁজে বের করে, সেটার পেছনে একটা বছর ধাই করে উড়িয়ে দেবে, তারপর গালটা অনেকক্ষণ চুলকায়ে টুলকায়ে মনে করতে বসবে শেষ কবে দাঁড়ি কাটার সৌভাগ্য হয়েছিল। আবার আমরা ইনডাস্ট্রি প্রোগ্রামারদের মতও নই – যারা মোটামুটি একমাস ধরে একই চুইংগাম চাবাতে চাবাতে একটা বোরিং কোড অলস হাতে বসে বসে লিখতে থাকে। কোড লিখতে লিখতে ঘুমাই পড়ে, আবার ঘুম থেকে উঠে আবার একই কোড লিখতে থাকে।

আমরা কন্টেস্টে করি অনেক বেশি চাপের মধ্যে, আমাদের প্রবলেম পড়ে বুঝতে হয় কি চাওয়া হচ্ছে, আমাদের অ্যালগরিদম ডিজাইন করতে হয়, আমাদের একটা কোড ডিজাইন করতে হয়, এবং আমরা সেটা করি মোটামুটি কোন ধরণের ফ্লোচার্ট হাবিজাবি না এঁকেই। এবং তারপর আমাদের কোডগুলো বসে বসে আমাদের ডিবাগও করতে হয়, টেস্টিং ও করতে হয়। তো ব্যাপারটা দাড়াচ্ছে, আমরা প্রবলেম সলভার, আমরা কম্পিউটার সায়েন্টিস্ট, আমরা কোডার, আমরা সফটওয়্যার আর্কিটেক্ট, আমরা ডিবাগার – কিন্তু আমরা পুরোপুরি এগুলোর কিছুই নই। কিন্তু একই সাথে আমরা এগুলোর সবকিছু।

পেতর মিত্রিচেভ বলতো, কন্টেস্ট প্রোগ্রামাররা হচ্ছে ফরমুলা ওয়ান রেসের ড্রাইভারদের মত। যে লোকটা একটা ট্রাক চালায়, সেও একটা ড্রাইভার, আর যে ফরমুলা ওয়ানে গাড়ি চালায় সেও ড্রাইভার, কিন্তু দুটার মধ্যে আকাশ পাতাল পার্থক্য। আমরা ভাবতেই পারি ফরমুলা ওয়ানে একটা গাড়ি নিয়ে ফালাফালি করার মধ্যে এমন কি আছে, বরং ট্রাক চালানোই অনেক কাজের। কিন্তু দুইটার মধ্যে ঠিক এভাবে তুলনা করা যায় না। যারা একবার ফরমুলা ওয়ানে গাড়ি ছোটানো শুরু করে, শুধু তারাই বুঝতে পারে এক্সাইটমেন্টটা কেমন, এবং সেটা কতটা আলাদা একটা বোকাসোকা হাইওয়েতে অন্ধকার রাতে তারা দেখতে দেখতে আর ঘুমাতে ঘুমাতে একটা স্টুপিড ট্রাক চালানোর সাথে।

এই লেখাটাতে আমি সি++ নিয়ে লিখবো। আর লিখবো কন্টেস্ট প্রোগ্রামারদের ঠিক কতটুকু সি++ জানা দরকার সেটা নিয়ে, আর ঠিক সেইটুকুই। কন্টেস্ট প্রোগ্রামাররা আর সবার মতো না, যে তাদেরকে একটা মোটাসোটা স্বাস্থ্যবান সি++ এর বই ধরিয়ে দিয়ে “নাচো” টাইপের কিছু একটা বলে আমি উধাও হয়ে যাবো। 

আর STL নিয়ে যা কিছু লিখবো তার বেশিরভাগ জুড়ে থাকবে ডাটা স্ট্রাকচার। আসলে কি, কম্পিউটারে আমরা প্রচুর ডাটা জমা করি। এখন ডাটাগুলোকে কম্পিউটারে কিভাবে রাখলে আমাদের কাজ করতে সুবিধা হবে, আমরা যদি সেটা ভেবে সেভাবে ডাটাগুলোকে সাজিয়ে রাখি, সেই বুদ্ধিমানের মত করে ডাটা সাজানোটাকেই আসলে ডাটা স্ট্রাকচার বলে।  একজন নতুন কন্টেস্ট্যান্টের কাছে ডাটা স্ট্রাকচার নিয়ে লাফালাফি করাটা খুব অদ্ভূত দেখাবে। এবং আমি যদি পুরোপুরি সবকিছুই ব্যাক্ষা করতে যাই, যে কোনটা কেন দরকার, কিভাবে দরকার, তাহলে এই লেখাটা বিশাল হয়ে যাবে আর আমার আঙ্গুল ব্যাথা করবে এটা লিখতে। তো আমি সব লিখে যাচ্ছি, যাতে তুমি শুধু জিনিসগুলো জেনে রাখতে পারো, কোন না কোন দিন হঠাৎ দেখবে একটা প্রবলেম সলভ করতে তোমার কিছু জানা ডাটা স্ট্রাকচার ব্যবহার করতে হচ্ছে! :)

প্রথম অংশ – সি++ নিয়ে বকরবকর

স্ট্রাকচার

আমাদের মাঝে মাঝেই একসাথে অনেকগুলো ডাটা রাখতে হয়। ধরো, তোমার ফোনবুকে প্রতিটা নামের সাথে একটা করে নাম্বার আছে। খুব সহজ। সমস্যাটা হয়ে গেলো, পৃথিবী অনেকটুকু  এগিয়ে গেছে, এখন আর কেউ বাটন গুতোগুতি করে ফোন করে না, সবাই ধাই ধাই করে মেইল করে। তো তোমার ফোন নাম্বারের পাশাপাশি মেইল অ্যাডরেসও রাখার দরকার হচ্ছে। তো ব্যাপারটা কি দাঁড়াচ্ছে, তুমি একই সাথে দুইটা ডাটা রাখছো। 

আমরা এই জিনিসটাকে বলি স্ট্রাকচার। এটা লিখি অনেকটা এভাবে।

struct data {
    char name[20];
    int number, email_num;
};

অবশ্যই ইমেইল আইডি ইনটেজার হয় না – আমি শুধু বোঝানোর লিখছি।
তো আগে আমাদের কিছু ডাটা টাইপ ছিল int, char, double এই ধরনের। আমরা এইমাত্র আমাদের নিজেদের জন্য একটা ডাটা টাইপ তৈরী করলাম, যার নাম হচ্ছে data । ডাটা হচ্ছে একটা মিষ্টির প্যাকেট যার মধ্যে বিভিন্ন ধরণের অনেকগুলো মিষ্টি আছে।এভাবে চিন্তা করলে যদি দেখো তোমার খুব মিষ্টি খেতে ইচ্ছে করছে, তাহলে চিন্তা করো, data হচ্ছে একটা বাক্স যেটার ভিতর আরো কিছু বাক্স(char, int) আছে।

মাঝে মাঝে আমাদের একই জিনিস বারবার ব্যবহার করতে হয়। ধরো, তোমার প্রতিদিন কিছু নতুন মানুষের সাথে দেখা হচ্ছে, ওরা হচ্ছে তোমার নতুন ডাটা – কিন্তু নতুন মানুষগুলোই তোমার সবকিছু নয়, তোমার অনেক কাজ আছে করার মতো আর অনেক অনেক কিছু। তো তোমার দিনটা অনেকটা এরকম কিছু একটা হবে। 

struct day {
    data new_people[100];
    int total_new_people;
    worklist todo[100];
};

যেখানে worklist হয়তো আরেক টাইপের ডাটা। day হলো একটা বাক্স যেটার ভিতরে data  টাইপের কিছু বাক্সও আছে। 

ব্যাপারটা কঠিন লাগছে? হুমম, এটার নামই হলো অবজেক্ট অরিয়েন্টেড প্রোগ্রামিং। যারা প্রথম প্রথম এটা বুঝতে পারে, তারা তার পরের মোটামুটি কয়েক সপ্তাহ যেখানে সেখানে এটা নিয়ে আঁতলামি করতে খুব ভালোবাসে। তো জিনিসটা কঠিন লাগাটাই স্বাভাবিক। 

কিন্তু আমার মনে হয় না, জিনিসটা একটুও কঠিন। জিনিসটা ফালতু রকমের সোজা। আমরা একটা বাক্সের ভিতর আরেকটা বাক্স ভরতেই পারি, আমাদের যত ইচ্ছে খুশি, ততগুলো বাক্সের ভিতর ততগুলো করে বাক্স ভরে, তারপর ওই বাক্সগুলোর ভিতর আরো গাদা গাদা বাক্স ভরতেই পারি। তারপর যখন মনে হবে “উরি বাবা, পাগল হয়ে যাচ্ছি”, তখন উইনঅ্যাম্প খুলে অর্ণবের গান শুনতেই পারি, (যে অলরেডি অবজেক্ট অরিয়েন্টেড প্রোগ্রামিং পড়তে গিয়ে পাগল হয়ে গেছে)

বাক্সে বাক্সে বন্দি বাক্স
বাক্সে বাক্সে বন্দি বাসা,
বাক্স নিয়ে টাক show করা,
বাক্সতে সব স্বপ্ন আশা।

অর্ণবের মত একটা ননকোডার মানুষ যদি এই জিনিস বুঝতে পারে, আমরা কেন পারবো না? আরে, আমরা হলাম গিয়ে কন্টেস্ট প্রোগ্রামার, এলিট ক্লাসের মানুষজন!

বেশতো, মূল ব্যাপারটা কিন্তু এরকমই। কিন্তু আরেকটু ভেবে দেখো, প্রতিদিন কি তুমি বসে বসে মাথার ভিতর খালি ডাটাই ঢুকাও, নাকি কিছু করোও? যদি কিছু করো, তবে সেটা অবশ্যই কিছু কাজ, তাই না? হয়তো তুমি ক্লাসে বসে বসে ক্লাসওয়ার্কও করো, হয়তো প্রতিদিন তোমার মিস তোমাকে এক গাদা অংক দেয়, তুমি বসে বসে যোগ করো। তো তখন ব্যাপারটা কি হচ্ছে 

struct day {    data new_people[100];    int total_new_people;    worklist todo[100];
    void charm_your_miss() {        while( true ) do_math();        while( true ) smile();    }
    void do_math() {        int a, b;        scanf(“%d %d”,&a,&b);        printf(“%d\n”, a+b );    }
    void smile() {        printf(” :) “);    }};
 
এটা হচ্ছে তোমার দিনেরই একটা অংশ, তাইনা? ডাটার পাশাপাশি তোমাকে কিছু কাজও রাখতে হচ্ছে। নাইলে আসলে মিসকে চার্ম করা যাচ্ছে না, এমনকি হাসাও যাচ্ছে না।

এখন যদি আমার শুধু একটা স্ট্রাকচারের কোন একটা ডাটা অ্যাকসেস করা লাগে। আমরা সেটা করি ডট অপারেটর দিয়ে। ধরো আমার শুধু দরকার total_new_people কে। সেটাকে ধরে আমি শুণ্য করে দিবো। তাহলে আমার মেইন এর ভিতর কোডটা হবে এমন।


int main() {    day a_bright_new_day, mora_day;    mora_day.total_new_people = 0;    return 0; // already more gesi! :(}
 

আচ্ছা, এখন ধরো, আমার দিনটা খুব সুন্দর, আমার মিসকে চার্ম করা লাগতেসে না, কারণ স্কুল ছুটি। তো আমি কি করবো, আমি সারাদিন বসে বসে বাবল ফুলাবো আর হাসবো। তো আমি একটা কাজ করবো, হাসবো। (বাবল ফুলানো অবশ্যই কোন কাজের কাজ না, তাই না? ;) ) তখন আমি কাজটাও করবো একই ভাবে। একটা ডট অপারেটর ধরে হাসি মেরে দিবো।

int main() {    day a_bright_new_day, mora_day;    while( true ) a_bright_new_day.smile();    return 0; // are baba, din to shesh hobei!}

তো এই হলো ঘটনা।

এখন সমস্যা হলো, প্রতিদিন কতকিছুই ঘটতে পারে। তার উপর ছেলেপুলে বড় হচ্ছে। এখন সবকিছু তো আর সবাইকে বলা যায় না, তো আমরা আসলে সব ডাটা এমন ভাবে রাখতে পারবো না, যে আজাইরা লোকজন এসে বলবে, “চিচিং ফাঁক! এই নাও ডট অপারেটর”, তারপর ডট অপারেটর দিয়ে আমাদের সব ডাটা মেরে দিবে।

এই জিনিসটা এড়ানোর জন্য আমরা একটা কি-ওয়ার্ড ব্যবহার করি। চিচিং ফাঁক এর ঠিক উল্টা। এটা হলো – private। তোমার প্রাইভেট জিনিসপাতিতে কারো সাধ্য নাই হাতাহাতি করার। ;) তো জিনিসটা তখন লিখে এভাবে।

struct day {
    data new_people[100];
    int total_new_people;
    worklist todo[100];
    
    private:
        sweetthings bolbo_keno[100];
   
};

জিনিসপাতি পাবলিক করতে চাইলেও কোন সমস্যা নাই। পাবলিক করে দিলেই হবে। সেটা লিখতে হবে এভাবে।


struct day {    data new_people[100];    int total_new_people;    worklist todo[100];
    public:        sweetthings bolboi_to[100];
};

এবার একটু জ্ঞান কপচাই। সি++ এ, একটা ফাউ জিনিস আছে, সেটার নাম হলো ক্লাস। ক্লাস একটু মুরুব্বি টাইপের জিনিস। একইভাবেই লিখেও যদিও তারপরও।

class day {    data new_people[100];    int total_new_people;    worklist todo[100];
    public:        sweetthings bolbo_na_vabsilam[100];
};

ক্লাসের ব্যাপারটা হলো, তুমি যদি কিছু না বলে দাও ক্লাস সম্বন্ধে তাইলে ক্লাসের সব ডাটা প্রাইভেট থাকবে। আর স্ট্রাকচারের ক্ষেত্রে ঠিক উল্টা, ওর সব কিছুই পাবলিক, বলে না দিলে। এইজন্যই বললাম, ক্লাস একটু মুরুব্বি টাইপের জিনিস, বেশি ভাবের উপর থাকে।

ফাংশন ওভারলোড

মাঝে মাঝেই আমাদের একই কাজ করতে হয়, অনেক আলাদা আলাদা ভাবে। ধরো নরমাল হাসির ব্যাপারটাই, আমরা একেকজনের সামনে একেকভাবে হাসি। হেডমাস্টারের সামনে গিয়ে খ্যাঁক খ্যাঁক করে হাসতে হাসতে গড়াই পড়ে যাই না আমরা। আবার বন্ধুদের সাথে মুখ টিপে টিপে লাজুক লাজুক হাসিও আমরা দেই না। তো ব্যাপারটা একই কাজ কিন্তু ভিন্ন ভিন্ন জায়গায় ভিন্ন ভিন্ন রকমের কাজ করতে হচ্ছে। 

একটা সহজ উদাহরণ হচ্ছে অ্যাবসলুট ভ্যালু নেয়া। কোন সংখ্যার শুধু মান নেয়াটাকে বলে অ্যাবসলুট ভ্যালু নেয়া। যেমন -২০ এর অ্যাবসলুট ভ্যালু হলো ২০। মাইনাস উড়ে গেছে।


int absolute_int( int x ) {    if( x < 0 ) return -x;    else return x;}

তো ধরো আমার long long এও একই কাজ করা লাগবে। তাইলে আমি লিখবো


long long absolute_ll( long long x ) {    if( x < 0 ) return -x;    else return x;}

সি++ এ দুইটা আলাদা নাম লেখা লাগে না। এরকম দুইটা একই নামের ফাংশন লিখে দিলেই হয়। সে নিজে নিজে বুঝে নিবে তোমার ডাটা টাইপ দেখে যে তুমি মুচকি হাসি দিতে চাচ্ছো, না খ্যাঁক খ্যাঁক করে হাসতে চাচ্ছো। 


long long absolute( long long x ) {    if( x < 0 ) return -x;    else return x;}int absolute( int x ) {    if( x < 0 ) return -x;    else return x;}

হেডার ফাইল

সি++ এ নেমস্পেস ব্যবহার করলে হেডার লিখার জন্য .h মারা লাগে না। সেটা যদি সি++ এর হয়, যেমন algorithm, তাহলে এটা লেখা হবে এভাবে।

#include <algorithm>
using namespace std;

কিন্তু সেটা যদি সি এর কিছু একটা হয়, আমরা শুরুতে c লিখে দিবো। যেমন stdio.h লেখা হয় এভাবে। 

#include <cstdio>
using namespace std;

সত্যি কথা আমি এসবের কিছুই করি না। আমার একটা জায়গায় যা কিছু মনে পড়ে, যার যার কথা মনে পড়ে, সবাইকে একসাথে লিখে রেখেছি। জাস্ট ধরে কথা বার্তা ছাড়াই একটা কপি মারি।

#include<cstdio>#include<sstream>#include<cstdlib>#include<cctype>#include<cmath>#include<algorithm>#include<set>#include<queue>#include<stack>#include<list>#include<iostream>#include<fstream>#include<numeric>#include<string>#include<vector>#include<cstring>#include<map>#include<iterator>using namespace std;

এই হলো আমার হেডারদের কাহিনী।

কিন কাউট!

আমি অবশ্য উচ্চারণ করি সি-ইন, সি-আউট।
তুমি যদি একজন সি কোডার হও, তুমি অবশ্যই scanf দিয়ে ইনপুট নাও, আর printf দিয়ে আউটপুট মারো। খুব স্বাভাবিক ব্যাপার, আরে এতে লজ্জা পাওয়ার কিচ্ছু নেই, সবাই তাই করে! কিন্তু ব্যাপারটা হলো, সি তে তোমাকে বলে দিতে হয় তুমি কি ধরণের ডাটা নিয়ে খেলছো, মনে রাখতে হয় %lld, %lu, %c, %s, %d, %lf এইরকম বিচ্ছিরি দেখতে অনেক অনেক কিছু। 

সিপিপিতে তুমি শুধু একটা সি-ইন মেরে দিবা, কিচ্ছু মনে রাখা লাগবে না।
যেমন এটা হলো একটা সি কোড

int main() {
    int murgi;
    double water;
    long long bank_balance;
    
    scanf(“%d %lf %lld”,&murgi, &water, &bank_balance);
    printf(“%d %lf %lld”,murgi, water, bank_balance);    

 return 0;
     
}

একই জিনিস সি-ইন সি-আউট দিয়ে লিখলে এরকম হবে। 

int main() {    int murgi;    double water;    long long bank_balance;
    cin  >> murgi >> water >> bank_balance;    cout << murgi << water << bank_balance;
    return 0; // ki ase jibone?

খালি একটাই সমস্যা। এরা একটু স্লো। কাম কাজ একটু বেশি ধীরে সুস্থ্যে করে। 

টেম্প্লেট

টেম্প্লেট কি জিনিস সেটা যদি তুমি বুঝতেই চাও, এই কোডটায় একটা উঁকি মারো। ভয় পেয়েছো? এটা হলো পৃথিবীর এখনকার এক নাম্বার কোডারটার কোড।

template<class T> inline T gcd(T a,T b)

আচ্ছা, এটা মোটামুটি নির্দোষই লাগছে, তাই না? 
আমরা একটু আগে ফাংশন ওভারলোডিং দেখলাম না? ওই জিনিসটাই আরেকভাবে করা যায়, টেম্প্লেট ব্যবহার করে। যেমন ওই অ্যাবসলুট ভ্যালুর কোডটা টেম্প্লেট দিয়ে লিখলে এরকম হতো


template<class T> T absolute( T x ) {
    if( x < 0 ) return -x;
    else return x;
}


মানে আমার দুই তিনবার একই ফাংশন আলাদা আলাদা করে ডাটাটাইপ পাল্টে লিখতে হতো না। আমি টেম্প্লেটটা দেখিয়ে নিলাম, এই জন্য যে, আমরা একটু পরে STL নিয়ে আঁতলামি শুরু করবো, STL এর সবকিছুতে টেম্প্লেট ব্যবহার করে লেখা, যাতে তুমি ইচ্ছামতো ক্লাস/স্ট্রাকচার ব্যবহার করে নিজের ডাটাটাইপ ব্যবহার করতে পারো, আর সেটা নিয়ে ইচ্ছামতো নাচানাচিও যেন করতে পারো।

C প্রোগ্রামিং বিট , বাইট , মেমোরি এড্রেস , কম্পাইলার

কেমন আছেন সবাই ? আবার দেখা হইয়ে গেলো C programing পোস্টে  এ । আগের পোস্টে এ আমি আপনাদের C Programing কি , কেন শিখবো এইসব ব্যাপারে বলেছিলাম । তবে C Programing শিখার জন্য আর অনেক কিছু জানার দরকার । আজকে আলোচনা করবো বিট, বাইট , কম্পাইলার ইত্যাদি বিষয়ে । তাহলে আর কথা না বাড়াই ।

বিট এবং বাইট কি ?

বিট এবং বাইট হল কম্পিউটার এর বিভিন্ন ডাটার অতিক্ষুদ্র একক । কম্পিউটার সাধারণত '০' আর '১' নিয়ে কাজ করে । অর্থাৎ কম্পিউটার বাইনারি পদ্ধতিতে কাজ করে । আর এই বাইনারি সিস্টেমে প্রতিটি ডাটার একক হল বিট । কিন্তু এই বিট কে শুধুমাত্র '০' আর '১' এর মাধ্যমে প্রকাশ করা যায় ।

তাই বাইনারি সিস্টেমের এই সীমাবদ্ধতাকে কাটানোর জন্য কতগুলু বিটকে এক করে ব্যাবহার করা হয় যাকে বলে বাইট । ৮ বিট = ১ বাইট  । অর্থাৎ ৮ টা বিট মিলে হয় ১ বাইট । অর্থাৎ যদি বলা হয় যে কোন Software মেমোরিতে যদি 5MB জায়গা দখল করে তার মানে হল যে সে মেমোরিতে ১০২৪*১০২৪*৫ বাইট  জায়গা দখল করল ।
  • ৮ বিট = ১ বাইট
  • ১০২৪ বাইট  = ১ কেবি
  • ১০২৪ কেবি = ১ এমবি
  • ১০২৪ এমবি = ১ জিবি
  • ১০২৪ জিবি = ১ টেরা বাইট
মনে রাখা দরকার যে কম্পিউটার একটা  অক্ষর রাখার জন্য মাত্র ১ বাইট  জায়গা নিবে ।
C programing

মেমোরি এড্রেস কি ?

মেমোরি হল একটা কম্পিউটারের প্রধান অংশগুলুর মধ্যে একটা । সাধারণত কম্পিউটার প্রতিটি ডাটা তার মেমোরি থেকে অপারেট করে। কিন্তু এই মেমোরি এড্রেস টা আসলে কি? আমরা যদি একটা ক্লাসরুম এর সকল ছাত্র-ছাত্রীকে এক একটা Cell বিবেচনা করি তাহলে দেখা যাবে যে প্রত্যেকরই একটি আলাদা বৈশিষ্ট্য আছে । তেমনি কম্পিউটারের মেমোরি হল একটা ইলেক্ট্রনিক ডিভাইস যা অনেকগুলা Cell এর সমষ্টি । প্রত্যেক টা Cell ই সমান ডাটা বহন করে । কিন্তু এখন কোন ডাটাটা কোন Cell  এ আছে সেইটা বুঝার জন্য আবার প্রত্যেকটা Cell এর ই আলাদা এড্রেস/ক্রমিক আছে যাকে বলা হয় মেমোরি এড্রেস ।

এখন কথা হল C প্রোগ্রাম লিখব কোথায় ? C প্রোগ্রাম লিখতে হলে আমাদের Compiler লাগবে ।

কম্পাইলার এবং ইন্টারপ্রিটার কি ?

আমরা জানি যে কম্পিউটার সুধু  মেশিন Language বুঝে । কিন্তু C Programing Language তো কম্পিউটার এর বোধগম্য না । তাই এমন কিছুর দরকার যেইটা কিনা এই ভাষা কে কম্পিউটার এর বোধগম্য করে দিবে । আর সেইতা করার জন্য আমাদের দরকার কম্পাইলার / ইন্টারপ্রিটার ।  কম্পাইলার  যেকোনো প্রগ্রামিং Language কে Computer Machine Language এ রুপান্তরিত করে তাকে কম্পিউটার এর ব্যাবহার উপযোগী করে তোলে । এখন কথা হল গিয়ে কম্পাইলার আর ইন্টারপ্রিটার যেহেতু একই কাজ করে তাহলে এদের মধ্যে পার্থক্য টা কোথায় ।
কম্পাইলার C Programing Language কে Compile করে তাকে Machine Code এ Convert করে Executable File তৈরি করে যা পরবর্তীতে সহজভাবে কোন কম্পাইলার ছাড়াই ব্যাবহার করা যায় ।কিন্তু Interpreter সম্পূর্ণ Code কে Machine Code এ রূপান্তরিত করে না যার ফলে প্রতিবার প্রোগ্রাম ব্যাবহারের জন্য Interpreter এর দরকার পরে ।আর তাছাড়া কম্পাইলার ইন্টারপ্রিটার থেকে অনেক দ্রুত কাজ করে । তাই ইন্টারপ্রিটার থেকে কম্পাইলার অনেক বেশি জনপ্রিয় ।

এখন কথা হল গিয়ে কি ধরনের Compiler ব্যাবহার করা ভাল । অনেক ধরনের Compiler আছে । আমার জানামতে বর্তমানে সবচেয়ে ভাল Compiler গুলুর মধ্যে
CodeBlock , Dev C++ , NetBeans IDE এবং Microsoft Visual Studio ই উল্লেখযোগ্য ।
আজকে এই পর্যন্তই । আবার দেখা হবে ।
========================= HAPPY PROGRAMING ==============================