অ্যারে
এই অধ্যায় দেখব আমরা অ্যারে নিয়ে। আগের অধ্যায় ছিলো ফাংশন নিয়ে। সাধারণত অ্যারে বলতে, একই টাইপের একাধিক ভেরিয়েবল একসাথে ব্যবহার করা বুঝায়। যেমন, আমরা একটি ভেরিয়েবল কে একটি বাক্স যদি ধরি তাহলে, একাধিক বাক্স পাশাপাশি একসাথে রেখে একটি গ্রুপ করে নাম দিয়ে কিছু মানুষ রেখে দিলেন, তাদের রক্ষণাবেক্ষণ করার জন্য। এখন আপনি যদি ঐ গ্রুপের পাঁচতম বাক্সে কিছু রাখতে চান বা ঐ বাক্স থেকে কিছু নিয়ে আসতে চান তাহলে, একজন কে বলে দিলেন পাঁচতম বাক্সে এটি রেখে দাও বা এই জিনিসটি নিয়ে আসো। কিন্তু যদি একটি বাক্স দিয়ে একটি করে গ্রুপ করতে চান তাহলে একশটি বাক্স হলে কিন্তু শুধু নামকরণ করতেই আপনার মেজাজ খারাপ হয়ে যেতে পারে। একইভাবে আমরা এতদিন প্রোগ্রামিংয়েও একটি একটি করে ভেরিয়েবল নিয়ে কাজ করেছি, কিন্তু যদি একশটি ভেরিয়েবলের দরকার হয় তাহলে নিশ্চয়ই কেও আমরা এতগুলো ভেরিয়েবল ডিক্লেয়ার ও করতে চাইব না। তাই প্রোগ্রামিংয়ে অ্যারের মাধ্যমে এই সমস্যার সমাধান করতে হয়।
int n;
int ar[10];
Fig 6.0 |
অ্যারে ডিক্লেয়ার করতে হয় এভাবে, int ar[10];। এখানে ব্র্যাকেটের মাঝে দশ মানে ar নামক গ্রুপে এখন দশটি ইন্টিজার টাইপের ভেরিয়েবল আছে। Fig 6.0 এর নিচের সারির মত। int n; মানে একটি বাক্স বা একটি ভেরিয়েবল। এখন আপনি যদি চান পাঁচতম বাক্সে একটি নাম্বার রাখবেন, ধরে নিলাম 25। তাহলে আপনাকে নাম্বারটি রাখতে হবে এভাবে, int ar[4] = 25;। এখন প্রশ্ন আসতে পারে, যত নাম্বার বাক্সে নাম্বারটি রাখব সেই নাম্বারটি ব্র্যাকেটের মাঝখানে দিলে ঐ নাম্বারের বাক্সটি ব্যবহার করতে পারব বুঝলাম কিন্তু, 5 নাম্বার বাক্সে রাখার জন্য 4 কেন লিখব? এর কারণ হচ্ছে, অ্যারেতে কম্পিউটার সবসময় বাক্সের নাম্বার দেওয়া শুরু করে 0 থেকে। মানে আপনি যদি, দশ সাইজের একটি অ্যারে ডিক্লেয়ার করেন তাহলে আপনাকে তার ভিতরের ভেরিয়েবল/বাক্সগুলোর নাম্বারিং ধরে নিতে হবে 0 থেকে 9 পর্যন্ত। নিচের ছবিতে দেখেন আমি দশ সাইজের একটি অ্যারে নিয়ে তাতে কিছু ভ্যালু রেখেছি এবং কম্পিউটার যেভাবে ভেরিয়েবলগুলোর নাম্বারিং করবে সেভাবে ধরে নিয়েছি।
Fig 6.1 |
তাহলে Fig 6.1 এ দেখতে পারছি পাঁচতম/4 নাম্বার ইনডেক্সে 25 আছে, প্রথম বাক্সে/0 নাম্বার ইনডেক্সে আছে 5 এবং দশম বাক্সে/9 নাম্বার ইনডেক্সে আছে 50। এখন একটি প্রোগ্রাম করে দেখি, যে প্রোগ্রাম এই দশটি নাম্বার অ্যারেতে রাখবে এবং কিছু নাম্বার প্রিন্ট করেও দেখাবে।
#include <iostream>
using namespace std;
int main() { int ar[10] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
cout << ar[0] << endl; cout << ar[1] << endl; cout << ar[8] << endl;
return 0; } Code: 6.0 |
আট নাম্বার লাইনে আমরা একসাথে অ্যারে ডিক্লেয়ার করে আবার দশটি নাম্বার ও রেখে দিয়েছি। এখানে যেহেতু অ্যারে সাইজ দশ দিয়েছি তাই দশটির বেশি নাম্বার কিন্তু রাখতে পারব না। তবে, কম রাখতে চাইলে তা পারব। একাধিক ভেরিয়েবল এভাবে একসাথে রাখতে চাইলে তাদের ব্র্যাকেটবন্ধী করে কমা দিয়ে আলাদা করে দিলেই হয়। এরপর আমরা 1, 2 ও 9 নাম্বার ইনডেক্সের ভ্যালু প্রিন্ট করেছি। এতক্ষণে হয়ত আপনার পরিষ্কার হয়ে যাওয়ার কথা যে আমি যদি, পাঁচ সাইজের একটি অ্যারে নেই তাহলে আমি শুধু শূন্য থেকে চার পর্যন্ত ইনডেক্স গুলোই ব্যবহার করতে পারব। তার বাইরে কিছু করতে পারব না কারণ আমি এর বাইরে কোন ভেরিয়েবল নেই নি। আপনি তাও ইনডেক্সের নাম্বার মাইনাস বা সাইজের থেকে বেশি দিয়ে দেখতে পারেন। যেমন, Code: 6.0 তে cout << ar[-2] << endl; cout << ar[15] << endl; ইত্যাদি দিয়ে দেখতে পারেন। এখন কি ঘটবে? হয়ত প্রোগ্রামের মাথা খারাপ হয়ে যেতে পারে অথবা গারবেজ ভ্যালু দিতে পারে। প্রোগ্রামের মাথা খারাপ হয়ে যাওয়া মানে কি? এর মানে আপনি যখন নেগেটিভ ইনডেক্স ব্যবহার করতে যাবেন তখন কম্পিউটার দেখবে নেগেটিভ ইনডেক্স ব্যবহারের কোন নিয়মকানুন ত তার নেই। যেহেতু বুদ্ধি নেই তাই মানুষের মত এরপরেও কোনমতে কাজ ও চালিয়ে দিবে না। তখন প্রোগ্রাম চলাই বন্ধ করে দিবে। একে প্রোগ্রামিংয়ে বলে Runtime Error। আরেকটি কারণে হতে পারে এটি, সেটি হচ্ছে আপনি যদি কোনকিছুকে শূন্য দিয়ে ভাগ করতে চান।
এখন আমরা চাই সবগুলো নাম্বার একসাথে প্রিন্ট করব। যেহেতু আমরা লুপ শিখেছি তাই নিশ্চয়ই আমরা নিজে ইনডেক্স নাম্বার দিয়ে দিয়ে দশটি cout লিখতে যাব না। 0 থেকে n-1(n মানে অ্যারে সাইজ) পর্যন্ত লুপ চালিয়ে দিলেই কিন্তু আমরা একটি ভেরিয়েবলের মাধ্যমে ইনডেক্স নাম্বারগুলোও পেয়ে গেলাম। এখন আমরা লুপের ভিতরে cout << ar[i] << endl; দিলেই হয়ে যাবে।
#include <iostream>
using namespace std;
int main() { int ar[10] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
int n = 10; int i;
for (i = 0; i < n; i++){ cout << ar[i] << ' '; } cout << endl;
return 0; } Code: 6.1 |
আশাকরছি কোন কনফিউশন নেই। এরপরেও বলি, i যখন 0 থাকবে তখন ar[i]; মানে ar[0] = 5; আবার, i যখন 4 থাকবে তখন ar[i]; মানে ar[4] = 25;।
এবার নাম্বারগুলো বিপরীতক্রমে প্রিন্ট করব। মানে, Code: 6.1 এ প্রিন্ট করেছিলাম এভাবে, 5 10 15 20 25 30 35 40 45 50 কিন্তু এবার 50 আসবে প্রথমে, এরপর 45 এভাবে 5 সবার শেষে। কাজটি করা কিন্তু খুব সহজ। আপনি লুপ শুধু n-1 থেকে শুরু করে 0 পর্যন্ত চালাবেন।
#include <iostream>
using namespace std;
int main() { int ar[10] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50};
int n = 10; int i;
// printing array in previous way for (i = 0; i < n; i++){ cout << ar[i] << ' '; } cout << endl;
// printing it now reverse way for (i = n-1; i >= n; i--){ cout << ar[i] << ' '; } cout << endl;
return 0; } Code: 6.2 |
এখন আপনাকে বলা হলো, প্রথমে n ইনপুট দেওয়া হবে এবং পরে আরো n টি নাম্বার ইনপুট দেওয়া হবে। তবে, n এর ভ্যালু কখনো 100 এর বেশি হবে না। আপনাকে ইনপুট নেওয়া n টি নাম্বার প্রিন্ট করতে হবে। আমরা অবশ্যই n টি নাম্বার একটি অ্যারেতে নিয়ে রাখব এবং পরে তা অ্যারে থেকে প্রিন্ট করে দিব। এখন আমরা কিন্তু নির্দিষ্ট করে জানিনা প্রতিবারই অ্যারেতে দশটি ভ্যালু আসবে কিনা। চল্লিশটিও আসতে পারে আবার একশটিও আসতে পারে। কিন্তু এটি জানি কখনোই একশটির বেশি দেওয়া হবে না। তাহলে আমরা আগে int ar[100]; ডিক্লেয়ার করে রাখতে পারি। এখন আমার কাছে একশটি ভেরিয়েবল আছে। আমি চাইলে এখান থেকে এখন যতগুলো ইচ্ছা ব্যবহার করতে পারব। ইনপুট নেওয়ার জন্যেও আমরা 0 থেকে n-1 পর্যন্ত লুপ চালিয়ে n টি ভ্যালু ইনপুট নিয়ে নিব এবং আগের মত করেই প্রিন্ট করে দিব।
#include <iostream>
using namespace std;
int main() { int n, i; int ar[100];
cout << "How many number you want in array: "; cin >> n;
cout << "Enter " << n << " elements: "; for (i = 0; i < n; i++){ cin >> ar[i]; }
for (i = 0; i < n; i++){ cout << ar[i] << ' '; } cout << endl;
return 0; } Code: 6.3 |
এখন একটি প্রশ্ন, Code: 6.3 তে মোট কতটি ভেরিয়েবল ব্যবহার করতে হয়েছে? এখন এই প্রোগ্রামে প্রথমে n তে একটি ভ্যালু ইনপুট নিয়েছেন ধরে নিলাম 3। তাহলে আরো তিনটি ভ্যালু ইনপুট নিতে হবে অ্যারেতে রাখার জন্য। এরপর যখন প্রথম ইনপুট দিবেন তখন i এর ভ্যালু 0 মানে ইনপুটটি ar[0]; ভেরিয়েবলে চলে যাবে, এরপরের ইনপুট টি ar[1]; ভেরিয়েবলে এবং শেষের ইনপুটটি ar[2]; ভেরিয়েবলে। তাহলে ইনপুট দিবেন এভাবে।
3
4 6 2
নিশ্চয়ই মনে আছে, ডাটা টাইপ অধ্যায়ে একটি সমস্যা সমাধান করেছিলাম। আপনি ও আপনার বন্ধুরা মিলে মরুভূমিতে পানি সমস্যায় পরেছিলেন। সেই সমস্যাটিই আমরা নতুন করে ভেবে দেখি। এবার আপনারা বন্ধু আছেন n জন। প্রত্যেকে কিছু পরিমাণ পানি নিয়ে এসেছিলেন, কেও কম বা কেও বেশি। যাত্রা শুরুর একদিন পর বুঝলেন যাদের কম আছে তারা শেষ পর্যন্ত হয়ত টিকতে পারবে না। যদি, যাদের বেশি আছে তারা কিছু ভাগাভাগি করেন তাহলে এই সমস্যার সমাধান হবে। এখন আপনি সিদ্ধান্ত নিলেন সবার পানি একসাথে করে তারপর প্রত্যেকে সমান ভাগে ভাগ করে নিবেন। এখন প্রত্যেকের ভাগে কত লিটার করে পানি পরবে তা বের করতে চান প্রোগ্রাম করে। এবার কাজটি একটু ভিন্ন। প্রত্যেকের কাছে কত লিটার করে পানি আছে তার একটি লিস্ট করে নিবেন। এরপর সব যোগ করে মোট ফ্রেন্ড সংখ্যা মানে n দিয়ে ভাগ করে দিলেই পেয়ে যাবেন। এখন লিস্ট ত আমাদের অ্যারেতে নিতে হবে। Code: 6.3 এর মতই। খালি যোগ ও ভাগের কাজটি বেশি করতে হবে। এখন অ্যারেতে int টাইপের ভ্যালু নিলে কি শতভাগ সঠিক আউটপুট পাওয়া যাবে?
#include <iostream>
using namespace std;
int main() { int n, i; double ar[100];
cout >> "Enter the number of your friends: "; cin >> n;
cout >> "Enter their water value: "; for (i = 0; i < n; i++){ cin >> ar[i]; }
double sum = 0; for (i = 0; i < n; i++){ sum += ar[i]; }
cout << fixed << setprecision(3); cout << "Average: " << sum / n << endl;
return 0; } Code: 6.4 |
আমরা প্রত্যেকের পানির পরিমাণ ইনপুট নিয়ে এরপর আবার sum নামের ভেরিয়েবলে সবগুলোকে যোগ করে রেখে দিচ্ছি। তার আগে আমাদের অবশ্যই মোট বন্ধুর সংখ্যা ইনপুট নিতে হবে। এরপর শুধু মোট বন্ধুর সংখ্যা বা n দিয়ে ভাগ করে প্রত্যেকের ভাগে কত লিটার করে পানি পাওয়া যাবে তা পেয়ে যাচ্ছি।
এবারের কাজটি হচ্ছে, একটি অ্যারে থেকে maximum ভ্যালুটি খুঝে বের করা।
#include <iostream>
using namespace std;
int main() { int n, i; int ar[100];
cout << "How many number you want in array: "; cin >> n;
cout << "Enter " << n << " elements: "; for (i = 0; i < n; i++){ cin >> ar[i]; }
int MAX = 0;
for (i = 0; i < n; i++){ if (MAX < ar[i]){ MAX = ar[i]; } }
cout << "Maximum element: " << MAX << endl;
return 0; } Code: 6.5 |
প্রোগ্রামটিতে আমরা আগেই MAX নামের ভেরিয়েবলে 0 কে রেখে 0 কেই সবথেকে বড় ধরে নিয়েছি। এখন শুধু অ্যারেতে থাকা প্রত্যেকটি ভ্যালুর সাথে চেক করে দেখব, অ্যারেতে থাকা ভ্যালুটি MAX এ থাকা ভ্যালুটির থেকে বড় কিনা। বড় হলে সেই ভ্যালুটি আমরা MAX তে রেখে দিব। এভাবে শেষে পেয়ে যাব অ্যারে থেকে সবথেকে বড় নাম্বারটি। এখন প্রশ্ন, নিচের নাম্বারগুলো ইনপুট দিলে কি সঠিক আউটপুট পাওয়া যাবে?
4
-3 -10 -1 -5
আমরা জানি পাওয়া যাবে না, কারণ আমরা 0 কে ম্যাক্সিমাম ধরে নিয়েছি যা আসলে অ্যারেতে থাকা ভ্যালু গুলোর থেকে বড়। তাই অ্যারেতে থাকা ম্যাক্সিমাম ভ্যালুটি MAX এ আসতে পারবে না কারণ কন্ডিশন মিথ্যা। এই সমস্যা থেকে বাঁচতে খুব সহজ একটি সমাধান হচ্ছে, অ্যারেতে থাকা যেকোন একটি ভ্যালুকেই ম্যাক্সিমাম ধরে নেওয়া। যেমন, int MAX = ar[0];। এখন ইনপুট যাই আসুক সঠিক উত্তর আসতে বাধ্য। এবার কি আপনি অ্যারে থেকে minimum নাম্বারটি বের করতে পারবেন? খুব সহজ।
আমরা আবার অ্যারে রিভার্স করব। তবে, এবার প্রিন্ট করার সময় n-1 থেকে 0 পর্যন্ত প্রিন্ট করা যাবে না। কাজটি কিন্তু কঠিন কিছু না। অন্য আরেকটি অ্যারেতে রিভার্স করে ভ্যালু গুলো রেখে দিব। মানে প্রথম অ্যারের 0 তম ইনডেক্সের ভ্যালু যাবে দ্বিতীয় অ্যারের n-1 ইনডেক্সে, প্রথম অ্যারের 1 তম ইনডেক্সের ভ্যালু যাবে দ্বিতীয় অ্যারের n-2 তম ইনডেক্সে, এভাবে চলবে। এরপর অ্যারে দুইটি প্রিন্ট করে দিলেই পার্থক্য দেখতে পারবেন।
#include <iostream>
using namespace std;
int main() { int n, i; int ar[100], arr[100];
cout << "How many number you want in array: "; cin >> n;
cout << "Enter " << n << " elements: "; for (i = 0; i < n; i++){ cin >> ar[i]; }
for (i = 0, j = n-1; i < n; i++, j--){ arr[i] = ar[j]; }
for (i = 0; i < n; i++){ cout << ar[i] << ' '; }cout << endl;
for (i = 0; i < n; i++){ cout << arr[i] << ' '; }cout << endl;
return 0; } Code: 6.6 |
এখন আপনার জন্য একটি কাজ হচ্ছে, অ্যারে রিভার্স করবেন। তবে, একটি অ্যারের বেশি ব্যবহার করা যাবে না আর আগের মতই প্রিন্ট করার সময় লুপ 0 থেকে শুরু করতে হবে।
সার্চ মানে ত কোন কিছু খুঝে বের করা। আপনি 1 থেকে 100 এর মাঝে একটি নাম্বার মনে মনে ধরে নিবেন। নাম্বারটি নিলেন 80। এখন আমাকে খুঝে বের হবে আপনি 1 থেকে 100 এর মাঝে কোন নাম্বারটি মনে মনে ভাবতেছেন। যেহেতু, আমি খুবই সাধারণ মানুষ তাই আমি জাদু করে বা অন্য কোন ভাবে আপনার মনের কথা বলে দিতে পারব না :|। কিন্তু আমি বারবার প্রশ্ন করতে পারব এই শর্তে আপনি রাজী। তাহলে আমি 1 থেকে শুরু করব। প্রথম প্রশ্ন করব, নাম্বারটি কি 1? আপনার উত্তর না। এরপরের প্রশ্ন, নাম্বারটি কি 2? এবারেও না। এভাবে যখন 80 পর্যন্ত যাব তখন আপনি বলবেন হ্যাঁ। তাহলে আমাকে মোট 80 টি প্রশ্ন করতে হয়েছে। এটাকে বলে লিনিয়ার সার্চ। লিনিয়ার সার্চ নিয়ে আর আলোচনা করব না। কারণ, একটু ভেবে দেখেন আপনি আসলে লিনিয়ার সার্চ পারেন। অ্যারে থেকে ম্যাক্সিমাম আর মিনিমাম ভ্যালু বের করেছেন আসলে লিনিয়ার সার্চ এর আইডিয়া ব্যবহার করেই।
তবে, এই অধ্যায়ে আমরা আরেকটি সার্চ অ্যালগরিদম বাইনারি সার্চ নিয়ে আলোচনা করব। এটি শুধু সার্চ অ্যালগরিদমেই না, প্রোগ্রামিংয়েরই অত্যান্ত গুরুত্বপূর্ণ একটি জিনিস। প্রথমেই প্রশ্ন আসতে পারে, লিনিয়ার সার্চ দিয়ে ত সার্চ শিখেই নিলাম। তাহলে, আবার বাইনারি সার্চ কেন? বা, বাইনারি সার্চ কী? উত্তর হচ্ছে লিনিয়ার সার্চ ব্যবহার করে 80 বের করতে আমাকে 80 টি প্রশ্ন করতে হয়েছে কিন্তু, বাইনারি সার্চ দিয়ে করলে 7 টির বেশি প্রশ্ন 1 থেকে 100 এর মাঝে থেকে কোন নাম্বার বের করার জন্যেই লাগত না। 7 টিই কেন? বাইনারি সার্চ দিয়ে 1 থেকে n পর্যন্ত নাম্বারগুলো থেকে নাম্বার খুঝে বের করতে log₂(n) সময় লাগে। এখানে, (log₂(128) = 7) >= (n = 100) >= (log₂(64) = 6) তাই ধরে নিয়েছি 7 টির বেশি প্রশ্ন করতে হবে না। log কি জিনিস এটি না জেনে থাকলে গুগল করে জেনে নিতে পারেন। এই অধ্যায়ে আর এটি নিয়ে আলোচনা করব না। হয়ত পরে সময় ও সুযোগ পেলে অন্য লেখায় বিস্তারিত আলোচনা করব। এখন, তাহলে দেখি বাইনারি সার্চ কীভাবে কাজ করে। বাইনারি সার্চ এর নিয়মে হচ্ছে,
স্টেপ ০ঃ শুরু করতে হবে, ছোট নাম্বার কে left ধরে এবং বড় নাম্বারকে right ধরে।
স্টেপ ১ঃ left ও right এ থাকা নাম্বার যোগ করে দুই ভাগ করবে।
স্টেপ ২ঃ ভাগফল যদি ভেবে নেওয়া নাম্বারের সমান হয় তাহলে নাম্বারটি পেয়ে গেছি। (কাজ শেষ)
স্টেপ ৩ঃ ভাগফল যদি ভেবে নেওয়া নাম্বারের থেকে বড় হয়, তাহলে ভাগফলকে এক কমিয়ে right ভেরিয়েবলে রেখে দিব। এরপর আবার স্টেপ ১।
স্টেপ ৪ঃ ভাগফল যদি ভেবে নেওয়া নাম্বারের থেকে ছোট হয়, তাহলে ভাগফলকে এক বাড়িয়ে left ভেরিয়েবলে রেখে দিব। এরপর আবার স্টেপ ১।
স্টেপ ৫ঃ যদি left এর ভ্যালু right এর থেকে বড় হয়ে যায় তাহলে ভেবে নেওয়া নাম্বারটি 1 থেকে n এর মাঝে নেই।
এবার তাহলে একটি প্রোগ্রাম দেখে নেই। যে প্রোগ্রামের কাজ হচ্ছে, 1 থেকে 100 এর মাঝে ভেবে নেওয়া নাম্বারটি আছে কিনা তা চেক করা। তবে এই প্রোগ্রমে বাইনারি সার্চের কাজ আমরা মেইন ফাংশনে করব না। আমরা যেহেতু ফাংশন শিখেছি তাই অন্য একটি ফাংশনে বাইনারি সার্চের কাজটি করে রাখব।
#include <iostream>
using namespace std;
bool Binary_search(int Left, int Right, int num){ while (Left <= Right){ int mid = (Left + Right) / 2;
if (num < mid) Right = mid-1; else if (num > mid) Left = mid+1; else return true; }
return false; }
int main() { int Left = 1; int Right = 100;
// we search this number; int num = 21;
bool check = Binary_search(Left, Right, num);
if (check == true){ cout << num < " Found in 1 to 100" < endl; } else { cout << num << " is not in 1 to 100" << endl; }
return 0; } Code: 6.7 |
মেইন ফাংশনের শুরুতে left এ সবথেকে ছোট মানে 1 রেখেছি এবং right এ সবথেকে বড় মানে 100 রেখেছি। এরপর num নামক ভেরিয়েবলে 21 রেখেছি কারণ, এটিই আসলে ভেবে নেওয়া নাম্বার এবং আমরা এটিই খুঝব। এরপর ফাংশন কল করে প্রয়োজনীয় ভ্যালুগুলো পাঠিয়ে দিয়েছি। ফাংশনে গিয়ে শুরুতেই লুপের ভিতরে স্টেপ ৫ এর কন্ডিশন, এরপর স্টেপ ১ এর কাজ করেছি। এরপর স্টেপ ৩ ও ৪ এবং শেষে স্টেপ ২। সবশেষে false রিটার্ন করে দিয়েছি যদি নাম্বারটি না পাওয়া যায় মানে এক্ষেত্রে স্টেপ ৫ সত্যি হতে হবে। আর যদি পাওয়া যায় তাহলে স্টেপ ২ থেকেই true রিটার্ন করে ফাংশন থেকে চলে যাবে। অ্যালগরিদমটি ব্যবহার করে একটু খাতা কলম নিয়ে 75 খুঝে বের করার জন্য ভেবে দেখতে পারেন তাহলে, আশাকরি পরিস্কার ধারণা পাবেন।
বাইনারি সার্চ এর অসুবিধা হচ্ছে এটি শুধু ছোট থেকে বড় ক্রমে বা বড় থেকে ছোট ক্রমে সাজানো সংখ্যার জন্যে কাজ করতে পারে। আগের প্রোগ্রামে এটি না বুঝা গেলেও যখন একটি অ্যারে থেকে কোন নাম্বার খুঝতে যাবেন তখন এটি ভালো করে ধরা পরবে। এখন কি কোড দেখার আগে বা নিচের লেখা পড়ার আগেই অ্যারে থেকে কোন নাম্বার বাইনারি সার্চ দিয়ে খুঝে বের করতে পারবেন?
এবার আমাদের অ্যারের পজিশনগুলো নিয়ে কাজ করতে হবে। বামপাশে থাকবে 0 (যেহেতু অ্যারে ইনডেক্স 0 থেকে শুরু) এবং ডানপাশে থাকবে n-1। আগে আমরা ভাগফলকেই কাঙ্খিত নাম্বার হিসেবে ধরে নিয়েছিলাম এখন ভাগফলকে কাঙ্খিত নাম্বারের পজিশন বা ইনডেক্স হিসেবে ধরে নিব। অ্যারেটিকেও ফাংশনে পাঠিয়ে দিব, সেটি কীভাবে? তা কোড দেখলেই আশাকরি বুঝে যাবেন।
#include <iostream>
using namespace std;
int Binary_search(int a[], int L, int R, int num){ while (L <= R){ int mid = (L + R) / 2;
if (a[mid] > num) R = mid-1; else if (a[mid] < num) L = mid+1; else return mid; }
return -1; }
int main() { int n, ar[101], i;
cin >> n;
for (i = 0; i < n; i++){ cin >> ar[i]; }
int num; cout << "Enter num to search: "; cin >> num;
int idx = Binary_search(ar, 0, n-1, num);
if (idx == -1){ cout << num << " is not in the array." << endl; } else { cout << num << " found and it's position " << idx+1 << endl; }
return 0; } Code: 6.8 |
আশাকরি, বাইনারি সার্চ বুঝতে পেরেছেন। তবে, আমি খুবই অল্প আলোচনা করেছি। আপনি প্রয়োজন অনুযায়ী পরে একটু খুঝাখুঝি করে শিখে নিতে পারেন। আপনি নিচের তিনটি প্রশ্নের উত্তর যন্ত্রের ভাষায় দিতে পারলে বুঝতে পারবেন আপনি বাইনারি সার্চ মোটামুটি পারেন।
1. Find the element from an array that is equal to num.
2. Find the minimum element from an array that is greater than or equal to num. (Lower bound)
3. Find the maximum element from an array that is less than or equal to num. (Upper bound)
আমরা লুপ অধ্যায়ে ম্যাট্রিক্সের কথা বলেছিলাম। এবার আমরা ম্যাট্রিক্স অ্যারেতে রাখব। যেমন, এই নাম্বাগুলো রাখব।
10 8 23
-3 35 5
7 23 31
কিন্তু একটি অ্যারেতে ত একটি লাইন রাখা যায় তাহলে, একাধিক লাইন রাখব কীভাবে? এখানের তিনটি লাইন কে এক লাইন ধরে একটি অ্যারেতে আপনি চাইলে রাখতে পারবেন তবে সেক্ষেত্রে লাইন নষ্ট হয়ে যাবে আর আমরা সেভাবে করবও না এখন। এর সমাধান হচ্ছে, অ্যারের ভিতরে অ্যারে। একাধিক ভেরিয়েবল যেমন আমরা একসাথে করে একটি অ্যারে বানাই তেমনি একাধিক অ্যারেও একটি অ্যারের ভিতরে রাখা যাবে। যেমন, 3X3 একটি ম্যাট্রিক্স অ্যারে পেতে চাইলে ডিক্লেয়ার করতে হবে এভাবে, int ar[3][3]; মানে এখানে তিনটি row এবং তিনটি coloumn বা, তিন সাইজের তিনটি অ্যারে। আবার 3X5 পেতে চাইলে ডিক্লেয়ার করতে হবে এভাবে, int ar[3][5];। এখানে, তিনটি row এবং পাঁচটি coloumn বা, পাঁচ সাইজের তিনটি অ্যারে। নিচের ছবিটি দেখলে আরো ভালো ধারণা পাবেন।
int ar[3][3];
Fig 6.2 |
এটি এখন খালি(যদিও খালি নয়, গারবেজ ভ্যালু আছে প্রত্যেক ঘরেই) মানে ডিক্লেয়ার করার পরে এমন একটি অ্যারে পাব। আর যদি উপরের ভ্যালুগুলো রাখি তাহলে দেখাবে নিচের ছবির মত।
int ar[3][3];
Fig 6.3 |
অ্যারের ইনডেক্স যেহেতু 0 থেকে শুরু হয় সেহেতু বলতে পারবেন 1 নাম্বার row এর 2 নাম্বার ভ্যালু কোনটি? উত্তর বলে দিব একদম শেষে। তার আগে অবশ্যই নিজে নিজে বের করার চেষ্টা করবেন। এখন তাহলে, প্রোগ্রামিংয়ে ইনপুট নিব কীভাবে? অ্যারের ভিতরে অ্যারেতে ইনপুট নেওয়ার জন্যে লুপের ভিতরে লুপ ব্যবহার করতে হবে, মানে Nested Loop। প্রোগ্রামটি দেখে নেই তাহলে।
#include <iostream>
using namespace std;
int main() { int ar[100][100]; int n;
cin >> n;
for (i = 0; i < n; i++){ for (int j = 0; j < n; j++){ cin >> ar[i][j]; } }
for (i = 0; i < n; i++){ for (int j = 0; j < n; j++){ cout << ar[i][j] << ' '; } cout << endl; }
return 0; } Code: 6.9 |
যখন i এর ভ্যালু 0 তখন প্রথম অ্যারে পুরোটাই ইনপুট নিয়ে নিবে। যেমন, ar[0][0], ar[0][1] & ar[0][2] ভেরিয়েবল গুলোতে। এরপর যখন i এর ভ্যালু 1 তখন দ্বিতীয় অ্যারে পুরোটাই ইনপুট নিয়ে নিবে। যেমন, ar[1][0], ar[1][1] & ar[1][2] ভেরিয়েবল গুলোতে। এভাবে সবগুলো অ্যারে ইনপুট নিয়ে নিবে। প্রিন্ট ও করবে একইভাবে। এখানে, প্রথমে n ইনপুট নিতে হবে, এবং পরে nXn টি ভ্যালু ইনপুট দিতে হবে।
এই যে অ্যারের ভিতরে অ্যারে, একে বলে 2D/Two Dimensional অ্যারে। প্রথমে যে অ্যারে নিয়ে আলোচনা করেছি তাকে বলে 1D অ্যারে। 2D অ্যারের ভিতরে যদি আবার অ্যারে রাখি তাহলে সেটি 3D অ্যারে। এভাবে 4D, 5D ইত্যাদি অ্যারে নিয়ে প্রয়োজনমত কাজ করা যায়।
আপনারা নিশ্চয়ই ম্যাট্রিক্সের ডায়াগোনাল চিনেন। না চিনে থাকলে নিচের ছবিটি দেখে নিন। ছবিতে নীল কালার করা ঘরগুলো কোণাকোণি যে রেখা প্রকাশ করেছে সেটিই ডায়াগোনাল।
int ar[3][3];
Fig 6.4 |
আমরা এখন, একটি nXn সাইজের অ্যারে থেকে তার ডায়াগোনালে থাকা ভ্যালু গুলোর যোগফল বের করে প্রিন্ট করব। যেমন উপরের ছবির ম্যাট্রিক্সের ডায়াগোনালের যোগফল, 10 + 35 + 31 = 76। খুব কঠিন মনে হচ্ছে কাজটি? আসলে একেবারে সহজ। খেয়াল করলে দেখবেন, যখন i এর ভ্যালু 0 এবং j এর ভ্যালু 0 তখন ডায়াগোনালের প্রথম ঘরটি পেয়ে যাচ্ছি(ar[0][0] = 5)। আবার যখন, i এর ভ্যালু 1 এবং j এর ভ্যালু 1 তখন ডায়াগোনালের দ্বিতীয় ঘরটি পেয়ে যাচ্ছি(ar[1][1] = 35)। এবং ডায়াগোনালের প্রত্যেকটি ঘর আসলে এভাবেই আসবে, মানে i এবং j সবসময় সমান হবে। আপনি আরো নিচের দিকে গিয়ে দেখতে পারেন। তাহলে লুপ চালিয়ে আমরা শুধু একটি কন্ডিশন দিয়ে দিব, if (i == j)sum += ar[i][j];। আশাকরছি কোড দেখার আগেই চেষ্টা করে দেখবেন এবং পারবেন এই সহজ কাজটি।
#include <iostream>
using namespace std;
int main() { int ar[101][101]; int n;
cin >> n;
for (i = 0; i < n; i++){ for (int j = 0; j < n; j++){ cin >> ar[i][j]; } }
int diagonal_sum = 0;
for (i = 0; i < n; i++){ for (int j = 0; j < n; j++){ if (i == j) diagonal_sum += ar[i][j]; } }
cout << diagonal_sum << endl;
return 0; } Code: 6.10 |
1 নাম্বার row এর 2 নাম্বার ভ্যালুটি হচ্ছে 5। এই অধ্যায় এই পর্যন্তই শেষ। এই সিরিজের পরের এবং শেষ অধ্যায়ে আলোচনা করব স্ট্রিং নিয়ে। বেশি বেশি প্র্যাক্টিস করুন। প্রোগ্রামিংয়ে ভালো করতে হলে বেশি বেশি প্র্যাক্টিসের আসলে বিকল্প নেই। আর কোন সমস্যা হলে নির্দ্বিধায় কমেন্ট করতে পারেন। শেষে একটি মজার তথ্য। খেয়াল করলে দেখবেন, Code: 6.8 এ ডাটা টাইপ, কন্ডিশন, লুপ, ফাংশন এবং অ্যারে সবই ব্যবহার করতে হয়েছে যা এ পর্যন্ত আমরা শিখেছি।
No comments