Thursday 3 March 2022

ইনসার্শন সর্ট(Insertion sort) অ্যালগরিদম

 

গত পর্বগুলোতে আমি সিলেকশন সর্ট(Selection sort) এবং বাবল সর্ট(Bubble sort) অ্যালগরিদম নিয়ে আলোচনা করেছিলাম এই পর্বে আরও একটি সহজ সর্টিং অ্যালগরিদম নিয়ে আলোচনা করবো নাম ইনসার্শন সর্ট(Insertion sort) ।

ইনসার্শন সর্ট(Insertion sort) অ্যালগরিদম :-

এই সর্টিং অ্যালগরিদমের মূল বিষয় হলো - একটি নির্দিষ্ট সংখ্যার জন্য এমন একটি জায়গা খুঁজে বের করা যেখানে সংখ্যাটিকে রাখলে তার আগের সংখ্যাটি তার থেকে ছোট বা সমান হবে এবং পরের সংখ্যাটি তার থেকে বড় হবে । তবে সংখ্যাটি যদি অ্যাঁরে বা লিস্টের সবচেয়ে ছোট বা বড় সংখ্যা হয় তাহলে তার জন্য সবার প্রথমে জায়গা করে দিতে হবে ।যেমন : - নিচের visualization টি লক্ষ্য করি :-


 

ধরি, আমাদের কাছে [10,30,40] এই অ্যাঁরেটি ছোট থেকে বড় ক্রমে সাজানো আছে । আমি এই অ্যাঁরেতে আরেকটি সংখ্যা যুক্ত করতে চাই সংখ্যাটি হলো 20 । এখন আমাকে 20 কে এমন এক জায়গায় বসাতে হবে যেখানে তার আগের সংখ্যা তার থেকে ছোট বা সমান হবে এবং তার পরের সংখ্যাটি তার থেকে বড় হবে ।

যদি অ্যাঁরেতে লক্ষ করি তাহলে দেখতে পারবো যে, সেই কাঙ্খিত জায়গাটি হচ্ছে 10 এর পরের অবস্থান কারণ, 20 থেকে 10 ছোট এবং 30 বড় । এখন যেহেতু 10 এর পরের অবস্থানে 30 আছে, তাহলে 30 এর জায়গায় 20 কে বসাতে হলে অ্যাঁরের শেষ থেকে অর্থাৎ 40 কে এক ঘর ডানে সরাতে হবে এখন 40 যেখানে ছিলো সেই ঘরটি কিন্তু ফাকা -

[10, 30, _, 40]

এরপর 30 কে এক ঘর ডানে সরাই - [10, _, 30, 40]

এখন ফাকা জায়গাটি কিন্তু 20 এর জন্য পারফেক্ট জায়গা অর্থাৎ, যে স্থানটি ফাকা তার আগের সংখ্যাটি 20 থেকে ছোট এবং পরের সংখ্যাটি 20 থেকে বড় । তাহলে ফাকা জায়গাটিতে 20 কে এসাইন করি -

[10, 20, 30, 40]

এতক্ষণ যে পদ্ধতিতে একটি সংখ্যা অ্যাঁরেতে সাজানো হলো এই পদ্ধতিকেই আমরা ইনসারশন সর্ট(Insertion sort) বলতে পারি ।

অ্যারে(Array) ও ইনসার্শন সর্ট(Insertion sort) -

তো চলুন এখন একটি এলোমেলো অ্যাঁরে বা লিস্টকে ইনসারশন সর্ট(Insertion sort) পদ্ধতিতে ছোট থেকে বড় ক্রমে বা Accending order এ সাজাই । ধরি, আমার কাছে একটি অ্যারে আছে -

 

[50, 20, 10, 30]

স্টেপ(০১) :- প্রথমে 50 এবং 20 এর মধ্যে ছোট সংখ্যার জন্য উপযুক্ত জায়গা খুঁজে বের করবো । এক্ষেত্রে, 20 কে 50 এর অবস্থানে বসাতে হবে তাই 50 কে এক ঘর ডানদিকে সরাই । এখন কিন্তু 50 এর জায়গা খালি তাই খালি জায়গায় 20 কে এসাইন করি -


[20, 50, 10, 30]

স্টেপ(০২) :- 50 এবং 10 এর মধ্যে 10 এর জন্য উপযুক্ত জায়গা খুঁজে বের করি । এক্ষেত্রে, অ্যারের প্রথমে 10 কে রাখতে হবে অর্থাৎ 20 এর অবস্থানে । তাই, প্রথমে 50 কে এক ঘর ডান দিকে সরাই - [20, _, 50, 30]

এখনও উক্ত ফাকা স্থানটি কিন্তু 10 এর উপযুক্ত জায়গা না তাই 20 কেও এক ঘর ডান দিকে সরাই - [_, 20, 50, 30] এখন ফাকা স্থানে অর্থাৎ 20 এর আগের ঘরে 10 এসাইন করি -

[10, 20, 50, 30]

স্টেপ(০৩) :- 50 এবং 30 এর মধ্যে 30 এর জন্য উপযুক্ত জায়গা খুঁজে বের করি এক্ষেত্রে, 20 এবং 50 এর মাঝে । তাই 50 কে এক ঘর ডানদিকে সরাই -

[10, 20, _, 50] এখন ফাকা জায়গাটিতে 30 কে এসাইন করি -

 


[10, 20, 30, 50]

ব্যাস, উপরোক্ত অ্যারে বা লিস্টটি ছোট থেকে বড় ক্রমে অর্থাৎ Accending order এ সাজানো হয়ে গেলো । এখন আপনি যদি বুঝতে না পারেন তাহলে খাতা-কলম নিয়ে বিষয়টি বোঝার চেষ্টা করতে পারেন । যদি প্রথম বা দ্বিতীয় বারে বিষয়টি বুঝে থাকেন তাহলে আপনি একটি বড় অ্যারে বা লিস্টকে খাতা-কলমে সর্ট করতে পারেন । তো চলুন এখন ইমপ্লিমেন্টেশন করা যাক -

In Python : 

def insertionSort(arr):
    for i in range(1, len(arr)):
        # arr[i] কে currentValue তে এসাইন করি
        currentValue = arr[i]
        # currentValue এর জন্য উপযুক্ত স্থান খুঁজে বের করি
        j = i - 1
        # যদি j, 0 থেকে সমান বা বড় হয় এবং  arr[j] থেকে currentValue ছোট হয়
        while j >= 0 and arr[j] > currentValue:
            # arr[j] কে তার পরের ঘরে রেখে দিই
            arr[j+1] = arr[j]
            # j এর মান 1 করে কমাই
            j -= 1
        # এখন খালি জায়গায় currentValue কে বসাই
        arr[j+1] = currentValue
    return arr

 

In JavaScript :

function insertionSort(arr) {
  // একটি currentValue নামে ভেরিয়েবল নিই
  var currentValue;
  // i এর মান 1 থেকে len(arr) এর আগ পর্যন্ত 1 করে বাড়াই
  for (var i = 1; i < arr.length; i++) {
    // arr[i] কে currentValue তে এসাইন করি
    currentValue = arr[i];
    // currentValue এর জন্য উপযুক্ত স্থান খুঁজে বের করি (j = i - 1)
    // যদি j, 0 থেকে সমান বা বড় হয় এবং  arr[j] থেকে currentValue ছোট হয়
    for (var j = i - 1; j >= 0 && arr[j] > currentValue; j--) {
      // arr[j] কে তার পরের ঘরে রেখে দিই
      arr[j + 1] = arr[j];
    }
    // এখন খালি জায়গায় currentValue কে বসাই
    arr[j + 1] = currentValue;
  }
  return arr;
}

আপনি চাইলে জাভাস্ক্রিপ্ট কোডে for লুপের পরিবর্তে while লুপ ব্যাবহার করতে পারেন ।

উপরোক্ত কোড বিশ্লেষণ :-

উপরের প্রোগ্রামে, প্রথমে i=1 থেকে অ্যারের লেন্থ পর্যন্ত লুপ চালিয়েছি । তারপর currentValue নামে একটি ভেরিয়েবলের মাঝে অ্যারের Present ভ্যালুকে রাখছি । এক্ষেত্রে কারেন্ট ভ্যালুটি যাতে হারিয়ে না যায় তা নিশ্চিত করছি কারণ পরবর্তীতে এই currentValue কেই তার যথাযথ স্থানে রাখতে হবে ।

তারপর ভেতরের লুপে j >= 0 এবং arr[j] > currentValue এইভাবে চেক করতেছি । এখানে, যদি j এর মান 0 থেকে ছোট হয় তাহলে আমি বুঝতে পারবো যে অ্যারে বা লিস্টের সব উপাদানই currentValue থেকে বড় । আবার, j এর মান যদি 0 থেকে বড় বা সমান হয় তাহলে দ্বিতীয় শর্তপরীক্ষা করা করবো অর্থাৎ arr[j] > currentValue ।

এখন যদি দ্বিতীয় শর্ত অর্থাৎ arr[j] > currentValue সত্য হয় তাহলে, arr[j] কে আমরা এক ঘর ডানে সরিয়ে দিব - arr[j + 1] = arr[j]

আবার, arr[j] > currentValue যদি মিথ্যা হয় তাহলে, লুপ থেকে বের হয়ে arr[j + 1] এ currentVal কে এসাইন করে দিব - arr[j + 1] = currentVal ইত্যাদি ।

যেকোনো অ্যালগরিদম বাঁ ডাটা-স্ট্রাকচারের মূল কনসেপ্ট যদি আপনি ভালোভাবে বুঝতে পারেন তাহলে যেকোনো প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যাবহার করেই ইমপ্লিমেন্ট করতে পারবেন । চলুন ইনসার্শন সর্ট(Insertion sort) অ্যালগরিদমের টাইম ও স্পেস কমপ্লেক্সিটি বের করা যাক -

টাইম কমপ্লেক্সিটি(Time Complexity) :

উপরোক্ত কোড লক্ষ করলে আশা করি টাইম কমপ্লেক্সিটি(Time Complexity) বলে দিতে পারবেন । এই অ্যালগোরিদমেরও টাইম কমপ্লেক্সিটি(Time Complexity) O(n2) ।

স্পেস কমপ্লেক্সিটি(Space Complexity) :

উপরের প্রোগ্রামে একটু খেয়াল করলে দেখতে পারবো যে, প্রোগ্রামে একটি লিস্ট বা অ্যারে প্যারামিটার হিসেবে নেওয়া হয়েছে । এবং যা কাজ-কারবার করা হয়েছে তা এই অ্যারে বা লিস্টের মধ্যেই । এই অ্যারে বা লিস্টে কিন্তু কোনো নতুন উপাদান সংযোজন, বিয়োজন ইত্যাদি কিছুই করা হয় নাই । তাহলে বলতে পারি অ্যারে বা লিস্টটি Constant । এখন আপনার কাছে আমার প্রশ্ন এই প্রোগ্রামের স্পেস কমপ্লেক্সিটি(Space Complexity) কত ?

আশা করি পেরেছেন হ্যাঁ স্পেস কমপ্লেক্সিটি(Space Complexity) হচ্ছে - O(1) ।

ব্রাভো, যদি এতদূর পর্যন্ত আপনি ঠিকঠাক ভাবে পড়ে থাকেন তাহলে আমি ধরে নিতেই পারি ইনসার্শন সর্ট(Insertion sort) অ্যালগরিদম সম্পর্কে ভালো একটা দখল চলে আসছে ।

যদি সত্যি বুঝে থাকেন তাহলে একটি কাজ করতে পারেন, উপরোক্ত অ্যারেটিকে আমি কিন্তু Accending Order অর্থাৎ ছোট থেকে বড় ক্রমে সাজিয়েছি এখন আপনি ইনসার্শন সর্ট(Insertion sort) অ্যালগরিদম ব্যাবহার করে অ্যারেটিকে Decending Order অর্থাৎ বড় থেকে ছোট ক্রমে সাজানোর চেষ্টা করবেন । খুবই সহজ একটি কাজ আশা করি পারবেন শুভকামনা রইলো ।

 

Share:

Friday 4 February 2022

বাবল সর্ট(Bubble sort) অ্যালগরিদম

 

গত পর্বে আমি সিলেকশন সর্ট(Selection sort) অ্যালগরিদম নিয়ে আলোচনা করেছিলাম এই পর্বে আরও একটি সহজ সর্টিং অ্যালগরিদম নিয়ে আলোচনা করবো নাম বাবল সর্ট(Bubble sort) ।

কম্পিউটার সায়েন্সে যতগুলো সর্টিং অ্যালগরিদম রয়েছে তার-মধ্যে সবচেয়ে সহজ অ্যালগরিদম বলা হয় বাবল সর্ট কে । তো চলুন আজাইরা ইন্ট্রো গল্প বাদ দিয়ে বাবল সর্ট(Bubble sort) অ্যালগরিদম নিয়ে আলোচনা করা যাক ।

বাবল সর্ট(Bubble sort) অ্যালগরিদম :-

এই অ্যালগোরিদমের মূল বিষয় হলো, পরপর দুইটি উপাদানের মধ্যে তুলনা করে তাদের ক্রম অনুসারে রাখা । যেমন : - নিচের visualization টি লক্ষ্য করি :-

ধরি, আমার কাছে একটি অ্যারে আছে [400,200,100,300] । এখন এই অ্যারেটি আমি বাবল সর্ট(Bubble sort) অ্যালগরিদম ব্যাবহার করে ছোট থেকে বড় ক্রমে অর্থাৎ Ascending Order এ সাজাতে চাই ।

উপরোক্ত অ্যারেতে মোট ৪টি উপাদান বাঁ সংখ্যা আছে । আপনি চাইলে যেকোনো সাইজের অ্যারে নিয়ে কাজ করতে পারবেন আমার সময় বাঁচানোর জন্য আমি কম সংখ্যক উপাদানসুমহের অ্যারেটি নিলাম । চলুন কাজে আসা যাক -

স্টেপ(০১) :- প্রথমে আমি অ্যারের প্রথম ২টি উপাদান নিবো সেক্ষেত্রে উপাদানগুল হলো 400 ও 200 । এখন এই ২টি সংখ্যার মধ্যে আমি তুলনা করবো যে সংখ্যাটি ছোট তাকে প্রথমে এবং বড় সংখ্যাটিকে তার পরে রাখবো । যেহেতু, 200 ছোট তাই 200 কে প্রথমে এবং 400 কে তার পরে রাখলাম এখন অ্যারেটি হবে -

[200,400,100,300]

স্টেপ(০২) :- এবার 400 এবং 100 এর তুলনা করবো সেক্ষেত্রে ছোট সংখ্যাটি 100 এবং বড় সংখ্যাটি 400 । তাহলে 100 কে আগে এবং 400 কে পরে রাখলাম -

[200,100,400,300]

স্টেপ(০৩) :- এবারে 400 এবং 300 এর মধ্যে তুলনা করি । 400 > 300 এক্ষেত্রে 300 ছোট এবং 400 বড় তাহলে 300 কে প্রথমে 400 কে পরে রাখি -

 [200,100,300,400]

এখন অ্যারেটি যদি লক্ষ করি, সবচেয়ে বড় সংখ্যাটি কিন্তু সবার শেষে চলে এসেছে । এখন এই শেষ উপাদান বাঁ সংখ্যাটি বাদে বাকি ৩টি সংখ্যার মধ্যে পুনরায় আগের মতো তুলনা করতে হবে ।

স্টেপ(০৪) :- 200 এবং 100 এর মধ্যে তুলনা করি এক্ষেত্রে 100 ছোট এবং 200 বড় সংখ্যা । তাহলে 100 কে প্রথমে এবং 200 কে তার পরের স্থানে রাখি -

 [100,200,300,400]

স্টেপ(০৫):-  200 ও 300 এর মধ্যে যদি তুলনা করি তাহলে 200 হবে ছোট এবং 300 হবে বড় সংখ্যা । এখন এদের স্থানের অদল-বদল করতে হবে অর্থাৎ 200 কে আগে এবং 300 কে পরের স্থানে রাখতে হবে কিন্তু অ্যারের দিকে লক্ষ করলে দেখতে পারবো যে 200 এবং 300 তাদের যথাযথ স্থানেই রয়েছে । 

 

[100,200,300,400]

স্টেপ(০৬) :- 100 ও 200 এর মাঝে তুলনা করি স্পষ্ট দেখতে পাচ্ছি 100 ও 200 তাদের যথাযথ স্থানেই রয়েছে । সাথে বাকি সংখ্যাগুলোও কিন্তু ঠিকঠাক স্থানেই রয়েছে । এ পর্যায়ে এসে বলতে পারি আমাদের অ্যারেটি সর্টেড অর্থাৎ ছোট থেকে বড় ক্রমে সাজানো আছে ।

 আশা করি, আপনারা বাবল সর্ট(Bubble sort) অ্যালগরিদম বুঝতে পেরেছেন যদি একবারে বুঝে না থাকেন তাহলে আরেকবার পড়তে হবে । চলুন এখন ইমপ্লিমেন্টেশন বাঁ কোড লিখা যাক -

In Python :-

def bubbleSort(arr):
    # i এর মান  0 থেকে len(arr) এর আগ পর্যন্ত ১ করে বাড়াই
    for i in range(len(arr)):

        # j এর মান 0 থেকে len(arr)-i-1 এর আগ পর্যন্ত ১ করে বাড়াই
        for j in range(0, len(arr) - i - 1):

            # arr[j] > arr[j+1] সত্য হয় তাহলে দুইটিকে অদল-বদল করি

            if arr[j] > arr[j+1]:
                arr[j], arr[j+1] = arr[j+1], arr[j]
    return arr

In JavaScript :-

const optimizedBubbleSort = (arr) => {
  // i এর মান  0 থেকে arr.length এর আগ পর্যন্ত ১ করে বাড়াই
  for (let i = 0; i < arr.length; i++) {
    // j এর মান 0 থেকে arr.length-i-1 এর আগ পর্যন্ত ১ করে বাড়াই
    for (let j = 0; j < arr.length - i - 1; j++) {
      // arr[j] > arr[j+1] সত্য হয় তাহলে দুইটিকে অদল-বদল করি
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
};

যেকোনো অ্যালগরিদম বাঁ ডেটা-স্ট্রাকচারের মূল কনসেপ্ট যদি আপনি ভালোভাবে বুঝতে পারেন তাহলে যেকোনো প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যাবহার করেই ইমপ্লিমেন্ট করতে পারবেন ।

চলুন বাবল সর্ট(Bubble sort) অ্যালগরিদমের টাইম ও স্পেস কমপ্লেক্সিটি বের করা যাক -

টাইম কমপ্লেক্সিটি(Time Complexity) :

উপরোক্ত কোড লক্ষ করলে দেখবো প্রথম লুপটি চলে i = 0 থেকে n পর্যন্ত । এবং ভেতরের অর্থাৎ ২য় লুপটি চলে j = 0 থেকে n-i-1 পর্যন্ত ।

  • যখন i = 0, তখন ভেতরের লুপটি চলে j = 0 থেকে j = n - i - 1 অর্থাৎ 3 বার ।

  • আবার i = 1 হলে, ভেতরের লুপটি চলে j = 1 থেকে j = n - i - 1 অর্থাৎ 2 বার ।

এভাবেই যতক্ষণ না লুপটি শেষ হয় চলতেই থাকবে ।

এখন আমরা খুব সহজেই বলে দিতে পারি যে, উক্ত প্রোগ্রামের টাইম কমপ্লেক্সিটি(Time Complexity) O(n*(n-i-1)) 

অর্থাৎ O(n*(n-1)) ।

=> n*(n - 1)

=> n2 - n

=> O(n2 - n)

O(n2 - n) কে আমরা O(n2) লিখতে পারি কারণ n2 এর তুলনায় n ছোট ।

স্পেস কমপ্লেক্সিটি(Space Complexity) :

উপরের প্রোগ্রামে একটু খেয়াল করলে দেখতে পারবো যে, প্রোগ্রামে একটি লিস্ট বা অ্যারে প্যারামিটার হিসেবে নেওয়া হয়েছে । এবং যা কাজ-কারবার করা হয়েছে তা এই অ্যারে বা লিস্টের মধ্যেই । এই অ্যারে বা লিস্টে কিন্তু কোনো নতুন উপাদান সংযোজন, বিয়োজন ইত্যাদি কিছুই করা হয় নাই । তাহলে বলতে পারি অ্যারে বা লিস্টটি Constant । এখন আপনার কাছে আমার প্রশ্ন এই প্রোগ্রামের স্পেস কমপ্লেক্সিটি(Space Complexity) কত ?

আশা করি পেরেছেন হ্যাঁ স্পেস কমপ্লেক্সিটি(Space Complexity) হচ্ছে - O(1) ।

ব্রাভো, যদি এতদূর পর্যন্ত আপনি ঠিকঠাক ভাবে পড়ে থাকেন তাহলে আমি ধরে নিতেই পারি বাবল সর্ট(Bubble sort) অ্যালগরিদম সম্পর্কে ভালো একটা দখল চলে আসছে ।

যদি সত্যি বুঝে থাকেন তাহলে একটি কাজ করতে পারেন, উপরোক্ত অ্যারেটিকে আমি কিন্তু Ascending Order অর্থাৎ ছোট থেকে বড় ক্রমে সাজিয়েছি এখন আপনি বাবল সর্ট(Bubble sort) অ্যালগরিদম ব্যাবহার করে অ্যারেটিকে Descending Order অর্থাৎ বড় থেকে ছোট ক্রমে সাজানোর চেষ্টা করবেন । 

খুবই সহজ একটি কাজ আশা করি পারবেন শুভকামনা রইলো ।

Share:

সিলেকশন সর্ট(Selection sort) অ্যালগরিদম


কোনো উপাদান বাঁ ডাটাসমূহকে একটি নির্দিষ্ট ক্রমে সাজানোর প্রক্রিয়াই হলো সর্টিং(Sorting) । সর্টিং(Sorting) আমরা দুই ভাবে করতে পারি -

 ১। Ascending Order

  এবং 

২। Descending Order

১। Ascending Order :-

ছোট থেকে বড় ক্রমে সাজানোর প্রক্রিয়াকে বলা হয় Ascending Order । যেমন :-

  • শ্রেণিকক্ষের হাজিরা খাতায় শিক্ষার্থীদের নামগুলো রোল নম্বর অনুযায়ী সাজানো থাকে ।

২। Descending Order :-

বড় থেকে ছোট ক্রমে সাজানোর প্রক্রিয়াকে বলা হয় Descending Order । যেমন :-

  • ফাইনাল পরীক্ষা শেষে রেজাল্ট শিটে শিক্ষার্থীদের নামগুলো মোট নম্বর অনুযায়ী বড় থেকে ছোট ক্রমে সাজানো থাকে ।

আসল কথায় আসা যাক, প্রোগ্রামিং করার সময় বিভিন্ন কাজে ডাটাসমূহকে এরকম সর্ট করার প্রয়োজন হয় । তখন আমরা খুব সহজেই বিভিন্ন সর্টিং অ্যালগরিদম ব্যাবহার করে ডাটাসমূকে সর্ট করে ফেলতে পারি । কম্পিউটার সায়েন্সে অনেক ধরণের সর্টিং অ্যালগরিদম আছে তারমধ্যে সহজ এবং জনপ্রিয় একটি সর্টিং অ্যালগরিদম হইলো সিলেকশন সর্ট(Selection sort) ।

সিলেকশন সর্ট(Selection sort) :-

এই সর্টিং অ্যালগরিদমের মূল বিষয় হলো, প্রতি ইটারেশনে ডাটাসমূহ থেকে একটি সঠিক উপাদানকে সিলেক্ট করা এবং তাকে অন্য আরেকটি উপাদানের সাথে অদল-বদল করে(যদি প্রয়োজন হয়) সঠিক জায়গায় এসাইন করা ।

নিচে  সিলেকশন সর্ট(Selection sort) এর  Visualization লক্ষ্য করুন :-

ধরি, আমাদের কাছে [100,400,300,600,500] এই অ্যারেটি আছে । এখন এই অ্যারেটিকে সিলেকশন সর্ট(Selection sort) অ্যালগরিদম ব্যাবহার করে Descending Order অর্থাৎ বড় থেকে ছোট ক্রমে সাজাতে হবে।

স্টেপ(১) :- প্রথমে উপরোক্ত অ্যারে থেকে সবচেয়ে বড় সংখ্যাটিকে সিলেক্ট করি এক্ষেত্রে 600 হচ্ছে সবচেয়ে বড় সংখ্যা । এখন 600 কে সবার প্রথমে নিয়ে আসতে হবে এজন্য অ্যারের প্রথম উপাদান 100 এর সঙ্গে 600 এর স্থান অদল-বদল করি । অদল-বদল শেষে আমাদের অ্যারেটি দাঁড়াবে এরকম -

[600,400,300,100,500]

স্টেপ(২) :- এখন অ্যারের দিকে লক্ষ করলে দেখতে পারবো যে, অ্যারের প্রথম উপাদানটি সবচেয়ে বড় । তাই প্রথম উপাদান বাদে অ্যারের বাকি উপাদানগুলোর মধ্যে সবচেয়ে বড় সংখ্যাটি সিলেক্ট করি এক্ষেত্রে সংখ্যাটি হচ্ছে 500 । এরপর 400 এর সাথে 500 এর  স্থান অদল-বদল করি তাহলে অ্যারেটি দাঁড়াবে -


[600,500,300,100,400]

স্টেপ(৩) :- অ্যারের প্রথম দুটি উপাদান সর্ট করা শেষ এখন বাকি তিনটি(300,100,400) উপাদান সর্ট করতে হবে । তাহলে এই তিনটি উপাদানের মধ্যে সবচেয়ে বড় সংখ্যাটি সিলেক্ট করি সংখ্যাটি হলো 400 । এরপর 300 এর সাথে 400 এর স্থান অদল-বদল করি এখন অ্যারেটি হবে -

[600,500,400,100,300]

স্টেপ(৪) :- এখন আমরা নিশ্চিত যে, অ্যারের প্রথম ৩টি উপাদান সর্টেড রয়েছে তাহলে বাকি ২টি(100,300) উপাদান থেকে সবচেয়ে বড় সংখ্যাটি সিলেক্ট করি এক্ষেত্রে সংখ্যাটি হচ্ছে 300 । এখন 100 এর সাথে 300 এর স্থান অদল-বদল করি । অদল-বদল শেষে অ্যারেটি হবে -

[600,500,400,300,100]

যেহেতু, অ্যারের ৫টি উপাদানের মধ্যে প্রথম ৪টি উপাদান বড় থেকে ছোট ক্রমে সাজানো । সেক্ষেত্রে আমরা নিশ্চিত যে, অ্যারের শেষ উপাদান অর্থাৎ 100 তার সঠিক জায়গাতেই আছে এর কোনো অদল-বদল করতে হবে নাহ । তাহলে আমাদের ফাইনাল অর্থাৎ সর্টেড অ্যারেটি হলো -

[600,500,400,300,100]

আশা করি, আপনারা সিলেকশন সর্ট(Selection sort) অ্যালগরিদমটি বুঝতে পেরেছেন যদি একবারে বুঝে না থাকেন তাহলে আরেকবার পড়তে হবে । চলুন এখন ইমপ্লিমেন্টেশন বাঁ কোড লিখা যাক -

পাইথনে ইমপ্লিমেন্টেশন :-

def selectionSort(arr):
    # i এর মান  0 থেকে len(arr) - 1 এর আগ পর্যন্ত ১ করে বাড়াই
    for i in range(len(arr) - 1):
        # largest নামে variable নিই এবং i এসাইন করি
        largest = i

        # j এর মান i+1 থেকে len(arr) এর পর্যন্ত ১ করে বাড়াই

        for j in range(i+1, len(arr)):

          # arr[largest] < arr[j] যদি সত্য হয় তাহলে largest এসাইন করি
            if arr[largest] < arr[j]:
                largest = j

        # যদি largest এবং i সমান না হয় তাহলে সংখ্যা দুইটি অদল-বদল করি
        if largest != i:
            arr[i], arr[largest] = arr[largest], arr[i]
    return arr

জাভাস্ক্রিপ্টে ইমপ্লিমেন্টেশন :-

const selectionSort = (arr) => {
  // i এর মান  0 থেকে arr.length - 1 এর আগ পর্যন্ত ১ করে বাড়াই
  for (let i = 0; i < arr.length - 1; i++) {
    // largest নামে variable নিই এবং i এসাইন করি
    let largest = i;
    // j এর মান i+1 থেকে arr.length এর পর্যন্ত ১ করে বাড়াই
    for (let j = i + 1; j < arr.length; j++) {

      // arr[largest] < arr[j] যদি true হয় তাহলে largest এ j এসাইন করি

      if (arr[largest] < arr[j]) {
        largest = j;
      }
    }

    // যদি largest এবং i সমান না হয় তাহলে সংখ্যা দুইটি অদল-বদল করি
    if (largest !== i) {
      [arr[i], arr[largest]] = [arr[largest], arr[i]];
    }
  }
  return arr;
};

যেকোনো অ্যালগরিদম বাঁ ডাটা-স্ট্রাকচারের মূল কনসেপ্ট যদি আপনি ভালোভাবে বুঝতে পারেন তাহলে যেকোনো প্রোগ্রামিং ল্যাঙ্গুয়েজ ব্যাবহার করেই ইমপ্লিমেন্ট করতে পারবেন ।

চলুন সিলেকশন সর্ট(Selection sort) অ্যালগরিদমের টাইম ও স্পেস কমপ্লেক্সিটি নিয়ে একটু অ্যানালাইসিস করা যাক -

টাইম কমপ্লেক্সিটি(Time Complexity) :

উপরোক্ত কোড লক্ষ করলে দেখবো প্রথম লুপটি চলে i = 0 থেকে n-1 পর্যন্ত । এবং ভেতরের অর্থাৎ ২য় লুপটি চলে j = i+1 থেকে n-1 পর্যন্ত ।

  • যখন i = 0, তখন ভেতরের লুপটি চলে j = 0 থেকে j = n - 1 অর্থাৎ 4 বার ।

  • আবার i = 1 হলে, ভেতরের লুপটি চলে j = 1 থেকে j = n - 1 অর্থাৎ 3 বার ।

  • i = 2 হলে, ভেতরের লুপটি চলে j = 2 থেকে j = n - 1 অর্থাৎ 2 বার । এভাবেই যতক্ষণ না লুপটি শেষ হয় চলতেই থাকবে ।

একটু লক্ষ করলে দেখতে পারবো যে, প্রথম লুপটি n সংখ্যক বার চললে তার ভেতরের লুপটি চলতেছে m সংখ্যক বার । তাহলে টাইম কমপ্লেক্সিটি(Time Complexity) দাঁড়াবে O(n *  m) । এখানে যেহেতু m এর মান n এর সমান তাহলে টাইম কমপ্লেক্সিটি(Time Complexity) বলতে পারি O(n  * n) বা O(n2) ।

স্পেস কমপ্লেক্সিটি(Space Complexity) :

উপরের প্রোগ্রামে একটু খেয়াল করলে দেখতে পারবো যে, প্রোগ্রামে একটি লিস্ট বা অ্যারে প্যারামিটার হিসেবে নেওয়া হয়েছে । এবং যা কাজ-কারবার করা হয়েছে তা এই অ্যারে বা লিস্টের মধ্যেই । এই অ্যারে বা লিস্টে কিন্তু কোনো নতুন উপাদান সংযোজন, বিয়োজন ইত্যাদি কিছুই করা হয় নাই । তাহলে বলতে পারি অ্যারে বা লিস্টটি Constant । এখন আপনার কাছে আমার প্রশ্ন এই প্রোগ্রামের স্পেস কমপ্লেক্সিটি(Space Complexity) কত ?

আশা করি পেরেছেন হ্যাঁ স্পেস কমপ্লেক্সিটি(Space Complexity) হচ্ছে - O(1) ।

ব্রাভো, যদি এতদূর পর্যন্ত আপনি ঠিকঠাক ভাবে পড়ে থাকেন তাহলে আমি ধরে নিতেই পারি সিলেকশন সর্ট(Selection sort) সম্পর্কে ভালো একটা দখল চলে আসছে ।

যদি সত্যি বুঝে থাকেন তাহলে একটি কাজ করতে পারেন, উপরোক্ত অ্যারেটিকে আমি কিন্তু Descending Order অর্থাৎ বড় থেকে ছোট ক্রমে সাজিয়েছি এখন আপনি সিলেকশন সর্ট(Selection sort) অ্যালগরিদম ব্যাবহার করে অ্যারেটিকে Ascending Order অর্থাৎ ছোট থেকে বড় ক্রমে সাজানোর চেষ্টা করবেন । 

খুবই সহজ একটি কাজ আশা করি পারবেন শুভকামনা রইলো 🥰।


Share:

Wednesday 2 February 2022

চেক প্যালিনড্রোম (Palindrome) - using Stack

 


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

আমরা জানি, Stack ডাটা-স্ট্রাকচার LIFO(Last In First Out) প্যারাডাইম মেনে চলে অর্থাৎ এখানে কোনো ভ্যালু শেষে এড করা হলে তা প্রথমে ডিলিট হয়ে যাবে । আপনি যদি Stack ও Queue ডাটা-স্ট্রাকচার সম্পর্কে না জেনে থাকেন তাহলে নিচের দেওয়া লিঙ্কগুলো থেকে পরে নিতে পারেন -

এখন, আসল কাজে ফিরে আসা যাক - আপনাকে একটি ফাংশন লিখতে হবে যা প্যারামিটার হিসেবে একটি স্ট্রিং নিবে । যদি স্ট্রিং টি Palindrome হয় তাহলে true নতুবা false রিটার্ন করবে ।

Palindrome String :-

যদি কোনো স্ট্রিং ডানে এবং বামে অর্থাৎ উভয় থেকে একই হয় তাহলে তাকে Palindrome String বলা যায় । যেমন :- mam, madam, racecar ইত্যাদি ।

এখন এই প্রব্লেমটি আমরা অনেক ভাবেই সমাধান করতে পারি আবার এক লাইনেও সমাধান করতে পারি । কিন্তু আমরা অন্যভাবে প্রব্লেমটি সমাধান না করে Stack দিয়ে কিভাবে সমাধান করতে হয় তা দেখবো এবং বোঝার চেষ্টা করবো ।

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

স্টেপ(০১) :- প্রথমে, "MaM" স্ট্রিং এর প্রত্যেকতা উপাদানকে একটি অ্যারে বা লিস্টে রাখতে হবে । সেক্ষেত্রে, আমাদের একটি ফাকা লিস্ট বা অ্যারে নিতে হবে -

contains = []

এরপর, স্ট্রিং এর প্রথম উপাদান "M" কে contains নামের অ্যারে বা লিস্টে এ পুশ করে দেই । এক্ষেত্রে, কিন্তু "M" উপাদানকে contains নামের অ্যারের শেষে রাখলাম । এখন অ্যারেটি যদি দেখি -

contains = ["M"]

স্টেপ(০২) :- এখন স্ট্রিং এর দ্বিতীয় উপাদান অর্থাৎ "a" কে contains নামের অ্যারে বা লিস্টে পুশ করে দেই । আবারও বলি পুশ করা মানে কিন্তু উপাদানকে অ্যারের শেষে যুক্ত করা এখন অ্যারেটি যদি আবার দেখি -

contains = ["M", "a"]

স্টেপ(০৩) :- স্ট্রিং এর শেষ উপাদান অর্থাৎ "M" কে contains নামের অ্যারে বা লিস্টে পুশ করে দিলাম -

contains = ["M", "a", "M"]

এখন লিস্ট বা অ্যারে থেকে প্রত্যেকটা উপাদান pop() করবো । pop() মানে হলো যে উপাদানটি আমরা সবার শেষে এড করেছি সেই উপাদান এখন সবার প্রথমে রিমুভ করে অন্য স্ট্রিং এ রাখবো । তারপর ফাংশনে প্যারামিটার হিসেবে পাওয়া স্ট্রিং এর সাথে তুলনা করে দেখবো যে স্ট্রিং টি Palindrome কি না ।

একটা ফাকা স্ট্রিং নিলাম word নামে - 

word = ""

এখন contains অ্যারে থেকে শেষের ভ্যালুকে রিমুভ অর্থাৎ pop() করে word স্ট্রিং এর মধ্যে রাখলাম । এখন contains অ্যারে হবে ২ উপাদান বিশিষ্ট এবং word স্ট্রিং টি হবে ১ উপাদান বিশিষ্ট -

word = "M" 

contains = ["M", "a"]

আবার, contains অ্যারে থেকে শেষের ভ্যালু রিমুভ অর্থাৎ pop() করে word এর মধ্যে রাখলাম -

word = "Ma" 

contains = ["M"]

এখন,  contains অ্যারে তে একটি মাত্র উপাদানই আছে সেইটাকেও রিমুভ অর্থাৎ pop() করে word এর মধ্যে রাখলাম -

word = "MaM" 

contains = []

এই word হলো আমাদের নতুন স্ট্রিং, এখন এই word এর সাথে function এর প্যারামিটার তুলনা করবো যদি দুইটা সমান হয় তাহলে true নতুবা false রিটার্ন করবে ।

যেহেতু, আমাদের প্যারামিটার এবং word এর মান একই সেহেতু "MaM" একটি Palindrome স্ট্রিং ।

আরেকটি উদাহরণ :-

ধরি আমাদের কাছে একটি str নামে স্ট্রিং আছে,

 str = "abc" ।

স্টেপ(০১) :- প্রথমে, "abc" স্ট্রিং এর প্রত্যেকতা উপাদানকে একটি অ্যারে বা লিস্টে রাখতে হবে । সেক্ষেত্রে, আমাদের একটি ফাকা লিস্ট বা অ্যারে নিতে হবে -

contains = []

এরপর, স্ট্রিং এর প্রথম উপাদান "a" কে contains নামের অ্যারে বা লিস্টে এ পুশ করে দেই । এক্ষেত্রে, কিন্তু "a" উপাদানকে contains নামের অ্যারের শেষে রাখলাম । এখন অ্যারেটি যদি দেখি -

contains = ["a"]

স্টেপ(০২) :- এখন স্ট্রিং এর দ্বিতীয় উপাদান অর্থাৎ "b" কে contains নামের অ্যারে বা লিস্টে পুশ করে দেই । আবারও বলি পুশ করা মানে কিন্তু উপাদানকে অ্যারের শেষে যুক্ত করা এখন অ্যারেটি যদি আবার দেখি -

contains = ["a", "b"]

স্টেপ(০৩) :- স্ট্রিং এর শেষ উপাদান অর্থাৎ "c" কে contains নামের অ্যারে বা লিস্টে পুশ করে দিলাম -

contains = ["a", "b", "c"]

এখন লিস্ট বা অ্যারে থেকে প্রত্যেকটা উপাদান pop() করবো । pop() মানে হলো, যে উপাদানটি আমরা সবার শেষে এড করেছি সেই উপাদান এখন সবার প্রথমে রিমুভ করে অন্য স্ট্রিং এ রাখবো । তারপর ফাংশনে প্যারামিটার হিসেবে পাওয়া স্ট্রিং এর সাথে তুলনা করে দেখবো যে স্ট্রিং টি Palindrome কি না ।

একটা ফাকা স্ট্রিং নিলাম word নামে - 

word = ""

এখন contains অ্যারে থেকে শেষের ভ্যালুকে রিমুভ অর্থাৎ pop() করে word স্ট্রিং এর মধ্যে রাখলাম । এখন contains অ্যারে হবে ২ উপাদান বিশিষ্ট এবং word স্ট্রিং টি হবে ১ উপাদান বিশিষ্ট -

word = "c" 

contains = ["a", "b"]

আবার, contains অ্যারে থেকে শেষের ভ্যালু রিমুভ অর্থাৎ pop() করে word এর মধ্যে রাখলাম -

word = "cb" 

contains = ["a"]

এখন, contains অ্যারে তে একটি মাত্র উপাদানই আছে সেইটাকেও রিমুভ অর্থাৎ pop() করে word এর মধ্যে রাখলাম -

word = "cba" 

contains = []

এই word হলো আমাদের নতুন স্ট্রিং, এখন এই word এর সাথে function এর প্যারামিটার তুলনা করবো যদি দুইটা সমান হয় তাহলে true নতুবা false রিটার্ন করবে ।

যেহেতু, আমাদের প্যারামিটার ছিলো "abc" এবং word এর মান "cba" সেহেতু "abc" একটি Palindrome স্ট্রিং নয়।

তো চলুন এখন কোড লিখা যাক -

জাভাস্ক্রিপ্টে ইমপ্লিমেন্টেশন -

const isPalindrome = (str) => {
  let contains = [];
  for (let i = 0; i < str.length; i++) {
    contains.push(str[i]);
  }

  let word = "";
  while (contains.length > 0) {
    word += contains.pop();
  }
  return word === str;
};

Output :

isPalindrome("MaM");  // true
isPalindrome("abc"); // false

পাইথনে ইমপ্লিমেন্টেশন :-

def isPalindrome(str):
    contains = []
    for item in str:
        contains.append(item)

    word = ""
    while len(contains) > 0:
        word += contains.pop()

    return word == str

Output :

isPalindrome("MaM"); # True
isPalindrome("abc"); # False

কোড বিশ্লেষণ :-

উপরোক্ত কোডে, প্রথমে contains নামে একটি অ্যারে বা লিস্ট নিয়েছি । তারপর, স্ট্রিং এ লুপ থ্রু করেছি এবং প্রত্যেকতা উপাদানকে contains নামের অ্যারে বা লিস্টে পুশ করে দিয়েছি ।

word নামে একটি ফাকা স্ট্রিং নিয়েছি এবং contains অ্যারেতে একটি লুপ থ্রু করেছি । লুপটি ততক্ষণ চলবে যতক্ষণ পর্যন্ত contains এর সাইজ 0 থেকে বড় থাকবে । এবং প্রত্যেক ইটারেশনে word এর সাথে contains এর শেষ উপাদানটি রিমুভ হয়ে যোগ হতে থাকবে । এক পর্যায়ে আমাদের লুপটি শেষ হবে । তখন যদি word এবং str সমান হয় তাহলে funciton টি আমাদেরকে true রিটার্ন করবে নতুবা false রিটার্ন করবে ।

কোডের টাইম ও স্পেস উভয় কমপ্লেক্সিটি হবে ওর্ডার অব এন অর্থাৎ O(n) ।

Share:

কিউ(Queue) ডাটা-স্ট্রাকচার ইন পাইথন

 


কম্পিউটার সাইন্সে আরও একটি কমন এবং বহুল ব্যবহৃত ডাটা-স্ট্রাকচার হলো Queue । আমরা আজকে এই ডাটা-স্ট্রাকচার সমন্ধে শিখতে যাচ্ছি, তবে আশা করি যে আপনি Stack ডাটা-স্ট্রাকচার সম্পর্কে জানেন।

যদি নাহ যেনে থাকেন তাহলে এখানে পড়ুন

- Queue কি ?

Queue একটি লিনিয়ার(Linear) ডাটা-স্ট্রাকচার যা FIFO প্যাঁরাডাইম(paradigm) মেনে চলে । FIFO এর পূর্ণরূপ হইলো - First In First Out অর্থাৎ Queue এ কোনো একটা ভ্যালু প্রথমে সংযোজন করা হইলে তা প্রথমেই বিয়োজন হবে। এখন একটু রিয়েল লাইফ উদাহরণ দেওয়া যাক -

- রিয়েল লাইফ উদাহরণ -

গত ব্লগে আপনার মামার মেয়ের তো বিয়ে হয়ে গেলো কিন্তু সেই বিয়েতে আপনি থালা বিতরন ছাড়া আর কিছুই করতে পারলেন নাহ । কিন্তু আপনি কি হাল ছেড়ে দেওয়ার মতো মানুষ ? নাহ অবশ্যই নাহ ।

হ্যাঁ আপনি আপনার মামাতো বোন কে পান নাই তাতে কি হয়েছে পৃথিবীতে কি মেয়ের অভাব নাকি ? তাই আপনিও আপনার মামার মেয়ের মতো বিয়ে করে ফেললেন । এখন আপনার মামাতো বোন কে তো দেখাতে হবে নাকি ? তাই আপনি প্ল্যান করলেন যে, হানিমুনে যাবেন দেশের কোথাও।

এই সুবাধে আপনি আগামিকালের টিকিট আজকেই বুক করতে গেলেন কিন্তু ওমা এ কি!

টিকিট কাউন্টারে তো অনেক লোক লাইন হয়ে দাঁড়িয়ে আছে । এবং তারা সিরিয়াল মোতাবেক একজনের পর একজন টিকিট নিচ্ছে । এখন আপনার সিরিয়াল ধরেন ১৮ নম্বর। তাহলে যখন আপনার সিরিয়াল আসবে তখনই আপনি টিকিট নিতে পারবেন ।

এখন আপনি মনে মনে ভাবতেছেন যে, ইস! যদি খানিকটা আগে আসতে পারতাম তাহলে আগেই যাইতাম । আসলেই, আগে আসলে আগেই যাইতে পারতেন । কিন্তু কি আর করার ।


 

আশা করি আপনি এখানে Queue ডাটা-স্ট্রাকচারের আচরণ ধরতে পেরেছেন । যদি এখনও আপনার খাটাস ব্রেইনে কিছু নাহ ঢুকে থাকে তাহলে চলেন আরেকটু বোঝা-বুঝি সেরে ফেলা যাক -

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

এভাবে পর পর ৬ জন মানুষ তাদের সিরিয়াল মেইন্টেইন করে টিকিট নিয়ে সেখান থেকে চলে যাবে। তাহলে বিষয়টা দাড়ালো যে, প্রথম যে মানুষটা লাইনে ইন হইলো সেই মানুষটাই প্রথমেই টিকিট নিয়ে লাইন থেকে আউট হয়ে গেলো । তাহলে কিন্তু এখানেও FIFO প্যাঁরাডাইম(paradigm) মেনে চললো অর্থাৎ - First In First Out।

- Common operations on Queue -

যে কোনো ল্যাংগুয়েজেই হোক নাহ কেনো Queue ইমপ্লিমেন্ট(implement) করার সময় মাস্ট(must) আমাদেরকে দুইটা মেথড তৈরি করতেই হবে-

  1. enqueue - Queue এ আইটেম সংযোজন ।
  2. dequeue - Queue থেকে আইটেম বিয়োজন ।

এইখানে মেথডস নেইম যে enqueue এবং dequeue ই হবে সেরকম বাধা-ধরা কোনো নিয়ম নেই । আপনি চাইলে add , remove বা আপনার সুবিধা-মতো যেকোনো নেইম দিতে পারেন । তবে এই দুইটা মেথড ছাড়াও Queue এ আমাদের প্রয়োজন মতো অনেক মেথডস তৈরি করতে পারি ।

- Queue এ আমরা যে মেথডস গুলো তৈরি করতে যাচ্ছি -

  1. enqueue() - Queue এ আইটেম সংযোজন ।
  1. dequeue() - Queue থেকে আইটেম বিয়োজন ।
  1. size() - Queue এ আইটেম কতগুলো আছে তা জানতে।
  1. isEmpty() - Queue খালি কি নাহ তা জানতে।

5। topElement() - Queue থেকে প্রথম আইটেম নেওয়া যাবে ।

6। tailElement() - Queue থেকে শেষ আইটেম নেওয়া যাবে ।

- Implementing a queue -

Queue ইমপ্লিমেন্ট(implement) করতে আমি লিস্ট(list) এবং ক্লাস(class) কে বেছে নিবো । তবে লিঙ্কড-লিস্ট(linked-list) দিয়েও চাইলে করতে পারেন । তবে, সামনের কোনোদিন সময় করে লিঙ্কড-লিস্ট(linked-list) দিয়ে কিভাবে Queue ইমপ্লিমেন্ট(implement) করতে হয় তা নিয়ে একটি Article লিখার চেষ্টা করবো ।

- ক্লাস(class) ডিফাইন -

class Queue :
    # code here

- কন্সট্রাক্টর(constructor) তৈরি -

def __init__(self) :
    self.data = []

এখানে একটি constructor ফাংশন নিয়েছি এবং data নামে একটা প্রোপার্টি নিয়েছি যা মুলত একটা লিস্টকে হোল্ড করে । এই লিস্টই মুলত Queue এর আইটেমগুলো কে কনট্রোল করবে ।

- enqueue() method -

এই মেথডের সাহায্যে কোনো আইটেমকে Queue এর প্রথমে সংযোজন করা যাবে ।

def enqueue(self, item):
    self.data.append(item)

লিস্টের append মেথডের সাহায্য নেওয়া হয়েছে যা এলিমেন্টকে খুব সহজেই Queue এ যুক্ত করে দিবে ।

- dequeue() method -

def dequeue(self):
    if len(self.data):
        return self.data.pop(0)
    else:
        return "dequeue failed!"

এখানে বলা হয়েছে যে যদি Queue এর লেন্থ শুন্য(0) থেকে বড় হয় তাহলে Queue থেকে শেষের এলিমেন্টকে ডিলিট করে দিবে। শেষের এলিমেন্ট সেইটাই যেইটা Queue এ প্রথমে এড করা হবে । আর বুঝতেই পারছি যে, শুন্য(0) থেকে বড় মানে Queue এ এলিমেন্ট আছে।

আর যদি Queue এ এলিমেন্ট নাহ থাকে তাহলে dequeue failed! রিটার্ন করবে ।

- size method -

Queue এ কতোগুলো আইটেম আছে তা এই সাইজ(size) মেথড রিটার্ন করবে ।

def size(self) :
    return len(self.data);

- isEmty method -

Queue খালি কি নাহ তা জানা যাবে isEmty() মেথডের এর সাহায্যে । যদি Queue এ আইটেম থাকে তাহলে false আইটেম নাহ থাকলে true রিটার্ন করবে।

def isEmpty(self):
    return len(self.data) == 0

- topElement method -

def topElement(self):
    if(len(self.data)):
        return self.data[0]
    else:
        return "queue is empty!"

Queue থেকে প্রথম এলিমেন্ট নেওয়া যাবে topElement মেথডের সাহায্যে ।

- tailElement method -

def tailElement(self):
    if(len(self.data)):
        return self.data[-1]
    else:
        return "queue is empty!"

Queue থেকে শেষ এলিমেন্ট নেওয়া যাবে tailElement মেথডের সাহায্যে ।

- Final Queue -

class Queue:
    # constructor
    def __init__(self):
        self.data = []

    # enqueue method
    def enqueue(self, item):
        self.data.append(item)

    # dequeue method
    def dequeue(self):
        if len(self.data):
            return self.data.pop(0)
        else:
            return "dequeue failed!"

    # size method
    def size(self):
        return len(self.data)

    # isEmpty method
    def isEmpty(self):
        return len(self.data) == 0

    # topElement method
    def topElement(self):
        if(len(self.data)):
            return self.data[0]
        else:
            return "queue is empty!"

    # tailElement
    def tailElement(self):
        if(len(self.data)):
            return self.data[-1]
        else:
            return "queue is empty!"

আপনি চাইলে Queue এ প্রয়োজন মতো আরও অনেক মেথড যুক্ত করতে পারেন । এখন আমাদের তৈরি করা Queue টেস্ট করে দেখবো যে সব কিছু ঠিকমতো কাজ করছে কি নাহ ।

- Create a Queue -

# create a queue
queue = Queue();

- Add Item To Queue -

queue.enqueue("shakil");
queue.enqueue("torikus");
queue.enqueue("morshed");
queue.enqueue("afifa");

# queue
[ 'afifa', 'morshed', 'torikus', 'shakil' ]

যেহেতু queue এ সর্বপ্রথমে shakil কে সংযোজন করা হয়েছে এখন যদি বিয়োজন করি তাহলে -

- Remove last item which is the first item -


print(queue.dequeue()); # shakil

# [ 'afifa', 'morshed', 'torikus' ]

যেহেতু queue এ সর্বপ্রথম shakil কে সংযোজন করা হয়েছে তাই dequeue() করার পর shakil কেই প্রথম বিয়োজন করে ফেলছে ।

- Length in Queue -

print(queue.size());
# 3

আমরা দেখতে পাইতেছি যে, queue এ তিনটি আইটেম আছে তাই আউটপুট হিসেবে 3 কেই রিটার্ন করা হয়েছে।

- Check if queue is empty -

print(queue.isEmty());
# false

যেহেতু, queue এ আইটেম আছে তাই আউটপুট হিসেবে false কেই রিটার্ন করা হয়েছে যদি আইটেম নাহ থাকতো তাহলে true রিটার্ন করতো। আমাদের queue ঠিক-ঠাক মতো কাজ করতেছে।

- শেষের কথা -

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

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

Share:

Tuesday 1 February 2022

ফাইন্ড ফ্যাক্টরিয়াল - Using Stack

 


আমরা জানি, Stack ডাটা-স্ট্রাকচার LIFO(Last In First Out) প্যারাডাইম মেনে চলে অর্থাৎ এখানে কোনো ভ্যালু শেষে এড করা হলে তা প্রথমে ডিলিট হয়ে যাবে । আপনি যদি Stack ও Queue ডাটা-স্ট্রাকচার সম্পর্কে না জেনে থাকেন তাহলে নিচের দেওয়া লিঙ্কগুলো থেকে পরে নিতে পারেন -

এখন, আসল কাজে ফিরে আসা যাক - আপনাকে একটি ফাংশন লিখতে হবে যা প্যারামিটার হিসেবে একটি নাম্বার নিবে এবং সেই নাম্বারের Factorial বের করে তা রিটার্ন  করতে হবে ।

Factorial Number:-

কোন সংখ্যার factorial number বলতে সেই সংখ্যা থেকে ১ পর্যন্ত সবগুলো সংখ্যার গুণফল কে বোঝায় যেমন :- 

= 5 

= 5 *4 * 3 * 2 *1

 = 120

এখন এই প্রব্লেমটি আমরা অনেক ভাবেই সমাধান করতে পারি । কিন্তু আমরা অন্যভাবে প্রব্লেমটি সমাধান না করে Stack দিয়ে কিভাবে সমাধান করতে হয় তা দেখবো এবং বোঝার চেষ্টা করবো ।

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

স্টেপ(০১) :- প্রথমে, 5 থেকে 1 পর্যন্ত প্রত্যেকতা সংখ্যাকে একটি অ্যারে বা লিস্টে রাখতে হবে । সেক্ষেত্রে, আমাদের একটি ফাকা লিস্ট বা অ্যারে নিতে হবে -

contains = []

এরপর, 5 থেকে 1 এর মাঝে প্রথম সংখ্যা অর্থাৎ 5 কে contains নামের অ্যারে বা লিস্টে এ পুশ করে দেই । এক্ষেত্রে, কিন্তু 5 কে contains নামের অ্যারের শেষে রাখলাম । এখন অ্যারেটি যদি দেখি -

contains = [5]

স্টেপ(০২) :- এখন, 5 থেকে 1 এর মাঝে দ্বিতীয় সংখ্যা অর্থাৎ 4 কে contains নামের অ্যারে বা লিস্টে পুশ করে দেই । আবারও বলি পুশ করা মানে কিন্তু উপাদানকে অ্যারের শেষে যুক্ত করা এখন অ্যারেটি যদি আবার দেখি -

contains = [5, 4]

স্টেপ(০৩) :- এবার , 5 থেকে 1 এর মাঝে তৃতীয় সংখ্যা অর্থাৎ 3 কে contains নামের অ্যারে বা লিস্টে পুশ করে দিলাম -

contains = [5, 4, 3]

স্টেপ(০৪) :- এবারে, 5 থেকে 1 এর মাঝে চতুর্থ সংখ্যা অর্থাৎ ২ কে contains নামের অ্যারে বা লিস্টে পুশ করে দিলাম -

contains = [5, 4, 3, 2]

স্টেপ(০৫) :- এবারে , 5 থেকে 1 এর মাঝে সবশেষ সংখ্যা অর্থাৎ 1 কে contains নামের অ্যারে বা লিস্টে পুশ করে দিলাম -

contains = [5, 4, 3, 2, 1]

এখন লিস্ট বা অ্যারে থেকে প্রত্যেকটা উপাদান pop() করবো । pop() মানে হলো যে উপাদানটি আমরা সবার শেষে এড করেছি সেই উপাদান এখন সবার প্রথমে রিমুভ করে অন্য একটি নাম্বারের সাথে গুণ করে দিবো ।

একটা নাম্বার নিলাম fact নামে এবং তার ভেতর 1 এসাইন করলাম - 

fact = 1

এখন, contains অ্যারে থেকে শেষের ভ্যালুকে রিমুভ অর্থাৎ pop() করে fact নাম্বারের এর সাথে গুণ করে দিলাম । এখন contains অ্যারে হবে ৪ উপাদান বিশিষ্ট এবং fact এর মান হবে 1*1 = 1 :-

fact = 1 

fact = 1*

fact = 1

contains = [5, 4, 3, 2]

আবার, contains অ্যারে থেকে শেষের ভ্যালু রিমুভ অর্থাৎ pop() করে fact এর সাথে গুণ করে দিলাম-

fact = 2 

fact = 1 *

fact = 2

contains = [5, 4, 3]

আবার, contains অ্যারে থেকে শেষের ভ্যালু রিমুভ অর্থাৎ pop() করে fact এর সাথে গুণ করে দিলাম-

fact = 3 

fact = 2 *

fact = 6

contains = [5, 4]

একইভাবে contains অ্যারে থেকে শেষের ভ্যালু pop() করে fact এর সাথে গুণ করে দিলাম-

fact = 4 

fact = 6 *

fact = 24

contains = [5]

এখন, contains অ্যারে তে একটি মাত্র সংখ্যা আছে সেইটাকেও pop() করে fact এর সাথে গুণ করে দিলাম -

fact = 5

fact = 2 *4 *

fact = 120

contains = []

এখন এই (fact = 120) ই হলো আমাদের কাঙ্খিত ফলাফল । এতো দূর পর্যন্ত আপনি যদি বুঝে থাকেন তাহলে আপনাকে Congrats আর যদি বুঝে নাহ থাকেন তাহলে আরেকবার পড়ুন এবং অন্য আরেকটি নাম্বারের Factorial বের করার চেষ্টা করুন ।

তো চলুন এখন কোড লিখা যাক -

পাইথনে ইমপ্লিমেন্টেশন :-

def fact(n):
    contains = []
    while n > 0:
        contains.append(n)
        n -= 1

    fact = 1
    while len(contains) > 0:
        fact *= contains.pop()

    return fact

Output :

print(fact(5))  # 120
print(fact(7))  # 5040

জাভাস্ক্রিপ্টে ইমপ্লিমেন্টেশন -

const fact = (n) => {
  let contains = [];
  while (n > 0) {
    contains.push(n);
    console.log(n);
    n--;
  }
  let fact = 1;
  while (contains.length > 0) {
    fact *= contains.pop();
  }
  return fact;
};

Output :

fact(5);  // 120
fact(7); // 5040

কোড বিশ্লেষণ :-

উপরোক্ত কোডে, প্রথমে contains নামে একটি অ্যারে বা লিস্ট নিয়েছি । তারপর, একটি লুপ থ্রু করেছি যতক্ষণ 0 থেকে n বড় হতে থাকবে ততক্ষণ লুপটি চলবে এবং প্রত্যেকতা সংখ্যাকে contains নামের অ্যারে বা লিস্টে পুশ করে দিয়েছি । n এর মান প্রত্যেক ইটারেশনে 1 করে কমে দিয়েছি ।

fact নামে একটি নাম্বার নিয়েছি তাতে 1 এসাইন করেছি এবং contains অ্যারেতে একটি লুপ থ্রু করেছি । লুপটি ততক্ষণ চলবে যতক্ষণ পর্যন্ত contains এর সাইজ 0 থেকে বড় থাকবে । এবং প্রত্যেক ইটারেশনে fact এর সাথে contains এর শেষ উপাদানটি রিমুভ হয়ে গুণ হতে থাকবে । এক পর্যায়ে আমাদের লুপটি শেষ হয়েছে । এখন, fact ভেরিয়েবলে আমাদের কাঙ্খিত factorial ভ্যালু রয়েছে তাই সেইটা রিটার্ন করেছি ।

কোডের টাইম ও স্পেস উভয় কমপ্লেক্সিটি হবে ওর্ডার অব এন অর্থাৎ O(n) ।

Share:

স্ট্যাক(Stack) ডাটা-স্ট্রাকচার ইন পাইথন

 

 

কম্পিউটার সাইন্সে কমন এবং বহুল ব্যবহৃত ডাটা- স্ট্রাকচার গুলোর মাঝে Stack একটি । আমরা আজকে এই ডাটা- স্ট্রাকচার সমন্ধে শিখতে যাচ্ছি, Stack কি তা জানার আগে একটু বোঝার চেষ্টা করি যে লিনিয়ার(Linear) ডাটা- স্ট্রাকচার কি ?

লিনিয়ার(Linear) ডাটা-স্ট্রাকচার কি ?

যেসব ডাটা- স্ট্রাকচারে ডাটা গুলো একটি নির্দিষ্ট সিকুয়েন্সিয়াল(sequential) অর্ডারে(order) থাকে অর্থাৎ ডাটা সমূহ নির্দিষ্ট ভাবে সাজানো গোছানো অবস্থায় রাখা হয় । যেখানে ডাটা সমূহ একটি আরেকটির সাথে কানেক্টেড থাকে এবং খুব দ্রুত বিভিন্ন অপারেশনসমূহ সম্পন্ন করা হয় যেমন - ট্রাভারসিং(Traversing), সার্চিং(Searching), মারজিং(Merging) ইত্যাদি তাদেরকেই লিনিয়ার(Linear) ডাটা- স্ট্রাকচার বলা হয়।

 

Stack কি ?

Stack একটি লিনিয়ার(Linear) ডাটা- স্ট্রাকচার যা LIFO প্যাঁরাডাইম(paradigm) মেনে চলে । LIFO এর পূর্ণরূপ হইলো - Last In First Out অর্থাৎ Stack এ কোনো একটা ভ্যালু শেষে সংযোজন করা হইলে তা প্রথমেই বিয়োজন হবে। এখন একটু রিয়েল লাইফ উদাহরণ দেওয়া যাক -

 

রিয়েল লাইফ উদাহরণ -

অনেক স্বপ্ন ছিলো আপনার মামার মেয়েকে বিয়ে করবেন কিন্তু আজ সেই মেয়ের বিয়ে। আমি খুবই দুঃখিত যে বরটা আপনাকে বানাতে পারলাম নাহ । তবে আপনি সেই বিয়েতে একজন ওয়ার্কার যে কিনা মেহমানদের মাঝে থালা(Plate) সার্ভ করার দায়িত্ব পালন করবেন ।

কিছুক্ষণ পর আপনি বেসিন থেকে কয়েকটি করে থালা হাতে নিয়ে আবার তা মেহমানদের মাঝে দিয়ে আসতেছেন । আপনি মুলত নাকের জলে চোখের জলে আজ এই কাজটাই পালন করতেছেন।

এইখানে একটা জিনিস খেয়াল করেছেন ? এই যে আপনি বেসিন থেকে থালা একটি একটি করে হাতে নিচ্ছেন এবং তা আবার একটি একটি করে মেহমানদের মাঝে সার্ভ করতেছেন ।


ধরি যে, এইবার আপনি ৮টি থালা বেসিন থেকে হাতে নিয়েছেন । যখন ৮টি থালার ১ম টি হাতে নিয়েছেন তখন আপনার হাতে থালা একটি । তারপর যখন ২ নাম্বার থালা হাতে নিলেন তখন আপনার হাতে থালা দুইটি এবং প্রথম যে থালাটা হাতে নিয়েছেন সেইটা কিন্তু এখন ২য় থালার নিচে। এভাবে পর্যায়ক্রমে আপনি ৮ টি থালা হাতে নিয়েছেন ।

তাহলে সবশেষে যে থালাটা হাতে নিলেন অর্থাৎ ৮ নাম্বার থালা সেইটা কিন্তু এখন সবার ওপরে । এবং প্রথমে যে থালাটা নিয়েছিলেন সেইটা কিন্তু এখন সবার শেষে । তাই নাহ ?

 


এখন আপনি ৮টি থালা মেহমানদের দিতে গেলেন এবং উপরের থালাটা একজনকে দিলেন । আপনি কিন্তু উপরের থালাটা অর্থাৎ ৮ নাম্বার থালাটা একজনকে দিয়ে দিলেন। তার মানে কি ? আপনি সবশেষে যে থালাটা আপনার হাতে নিয়েছিলেন সেই থালাটাই আপনি সর্বপ্রথম একজনকে দিয়ে দিলেন। এইভাবে পর্যায়ক্রমে আপনি সব থালায় মেহমানদের দিয়ে দিলেন ।

তাহলে সারমর্ম এই যে, বেসিন থেকে সর্বশেষে যে থালাটা আপনি হাতে নিয়েছিলেন তা সর্বপ্রথম হাত থেকে সরিয়ে ফেললেন । এবং সর্বপ্রথম যে থালাটা হাতে নিয়েছিলেন তা সর্বশেষে হাত থেকে সরিয়ে ফেললেন।

এখানেও কিন্তু  LIFO প্যাঁরাডাইম(paradigm) মেনে চললো অর্থাৎ - Last In First Out, শেষে যে থালাটা হাতে ইন করলেন প্রথেমেই সেইটাকে আউট করে দিলেন । আশা করি এখন আপনি Stack সম্পর্কে Theoretical একটা ধারণা পেলেন।

যেহেতু আমরা মোটামোটি বুঝি যে, Stack ডাটা- স্ট্রাকচার কি তাহলে চলুন এখন আমরা খুব সহজেই এইটা কে ইমপ্লিমেন্ট(implement) অর্থাৎ তৈরি করে ফেলি ।
 

- Stack ডাটা-স্ট্রাকচার ইমপ্লিমেন্ট(implement) করার আগে -

যে কোনো ল্যাংগুয়েজেই হোক নাহ কেনো Stack ইমপ্লিমেন্ট(implement) করার সময় মাস্ট(must) আমাদেরকে দুইটা মেথড তৈরি করতেই হবে -

১। push - Stack এ আইটেম সংযোজন ।

২। pop - Stack থেকে আইটেম বিয়োজন ।

এইখানে মেথডস নেইম যে push এবং pop ই হবে সেরকম বাধা- ধরা কোনো নিয়ম নেই । আপনি চাইলে add, remove বা আপনার সুবিধা- মতো যেকোনো নেইম দিতে পারেন ।

তবে এই দুইটা মেথড ছাড়াও Stack এ আমাদের প্রয়োজন মতো অনেক মেথডস তৈরি করতে পারি ।

- Stack এ আমরা যে মেথডস গুলো তৈরি করতে যাচ্ছি -

1। push() - stack এ আইটেম সংযোজন হবে।

2। pop() - stack থেকে আইটেম বিয়োজন হবে।

3। size() - stack এ আইটেম কতগুলো আছে তা জানা যাবে।

4। isEmpty() - stack খালি কি নাহ তা জানা যাবে।

5। topElement() - stack থেকে প্রথম আইটেম নেওয়া যাবে ।

6। tailElement() - stack থেকে শেষ আইটেম নেওয়া যাবে ।

- Stack ইমপ্লিমেন্ট(implement) -

Stack ইমপ্লিমেন্ট(implement) করতে আমি লিস্ট(list) এবং ক্লাস(class) কে বেছে নিবো । তবে লিঙ্কড-লিস্ট(linked-list) দিয়েও চাইলে করতে পারেন । সামনের কোনোদিন সময় করে লিঙ্কড-লিস্ট(linked-list) দিয়ে কিভাবে Stack` ইমপ্লিমেন্ট(implement) করতে হয় তা নিয়ে একটি Article লিখার চেষ্টা করবো ।

- ক্লাস(class) ডিফাইন -

class Stack:
    # code here

- কন্সট্রাক্টর(constructor) তৈরি -

def __init__(self):
    self.data = []

এখানে একটি constructor ফাংশন নিয়েছি এবং data নামে একটা প্রোপার্টি নিয়েছি যা মুলত একটা লিস্টকে হোল্ড করে । এই লিস্টই মুলত Stack এর আইটেমগুলো কে কনট্রোল করবে ।

- push method -

def push(self, item):
    self.data.append(item)

লিস্টের append মেথডের সাহায্য নেওয়া হয়েছে যা এলিমেন্টকে খুব সহজেই Stack এর শেষে যুক্ত করে দিবে ।

- pop method -

def pop(self):
    if(len(self.data)):
        return self.data.pop()
    else:
        return "Pop failed!"

এখানে বলা হয়েছে যে যদি Stack এর লেন্থ শুন্য(0) থেকে বড় হয় তাহলে Stack থেকে শেষের এলিমেন্টকে ডিলিট করে দিবে। শুন্য(0) থেকে বড় মানে Stack এ এলিমেন্ট আছে।

আর যদি Stack এ এলিমেন্ট নাহ থাকে তাহলে Pop failed! রিটার্ন করবে ।

- size method -

def size(self):
    return len(self.data)

Stack এ কতোগুলো আইটেম আছে তা এই সাইজ(size) মেথড রিটার্ন করবে ।

- isEmty method -

def isEmpty(self):
    return len(self.data) == 0

Stack খালি কি নাহ তা জানা যাবে isEmty এর সাহায্যে । যদি stack এ আইটেম থাকে তাহলে false আইটেম নাহ থাকলে true রিটার্ন করবে।

- topElement method -

def topElement(self):
    if(len(self.data)):
        return self.data[0]
    else:
        return "stack is empty!"

Stack থেকে প্রথম এলিমেন্ট নেওয়া যাবে topElement মেথডের সাহায্যে ।

- tailElement method -

def tailElement(self):
    if(len(self.data)):
        return self.data[-1]
    else:
        return "stack is empty!"

Stack থেকে শেষ এলিমেন্ট নেওয়া যাবে tailElement মেথডের সাহায্যে ।

- Final Stack -

class Stack:
    # constructor
    def __init__(self):
        self.data = []

    # push method
    def push(self, item):
        self.data.append(item)

    # pop method
    def pop(self):
        if(len(self.data)):
            return self.data.pop()
        else:
            return "Pop failed!"

    # isEmpty method
    def isEmpty(self):
        return len(self.data) == 0

    # size method
    def size(self):
        return len(self.data)

    # topElement method
    def topElement(self):
        if(len(self.data)):
            return self.data[0]
        else:
            return "stack is empty!"

    # tailElement
    def tailElement(self):
        if(len(self.data)):
            return self.data[-1]

        else:
            return "stack is empty!"

আপনি চাইলে stack এ প্রয়োজন মতো আরও অনেক মেথড যুক্ত করতে পারেন । এখন আমাদের তৈরি করা stack টেস্ট করে দেখবো যে সব কিছু ঠিকমতো কাজ করছে কি নাহ ।

- Create a Stack -

stack = Stack()

- Add Item To Stack -

stack.push('torikus')
stack.push('fahim')
stack.push('afifa')

# ['torikus', 'fahim', 'afifa']

stack এ সবশেষে afifa কে সংযোজন করা হয়েছে এখন যদি বিয়োজন করি তাহলে -

- Remove Last Item To Stack -

print(stack.pop())  # 'afifa'
# [ 'torikus', 'fahim' ]

যেহেতু stack এ সবশেষে afifa কে সংযোজন করা হয়েছে তাই pop() করার পর afifa কেই প্রথম বিয়োজন করে ফেলছে ।

- Length In Stack -

print(stack.size())  # 2

যেহেতু, stack এ দুইটি আইটেম আছে তাই আউটপুট হিসেবে 2 কেই রিটার্ন করা হয়েছে।

- Check If Stack Is Empty -

print(stack.isEmty())
# false

যেহেতু, stack এ আইটেম আছে তাই আউটপুট হিসেবে false কেই রিটার্ন করা হয়েছে যদি আইটেম নাহ থাকতো তাহলে true রিটার্ন করতো।

আমাদের stack ঠিক-ঠাক মতো কাজ করতেছে। আশা করি আপনি বুঝতে পেরেছেন ।

- শেষের কথা -

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

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

Share:

Sunday 30 January 2022

Queue data structure in javascript

 


কম্পিউটার সাইন্সে আরও একটি কমন এবং বহুল ব্যবহৃত ডাটা-স্ট্রাকচার হলো Queue । আমরা আজকে এই ডাটা-স্ট্রাকচার সমন্ধে শিখতে যাচ্ছি, তবে আশা করি যে আপনি Stack ডাটা-স্ট্রাকচার সম্পর্কে জানেন।

যদি নাহ যেনে থাকেন তাহলে এখানে পড়ুন

- Queue কি ?

Queue একটি লিনিয়ার(Linear) ডাটা-স্ট্রাকচার যা FIFO প্যাঁরাডাইম(paradigm) মেনে চলে । FIFO এর পূর্ণরূপ হইলো - First In First Out অর্থাৎ Queue এ কোনো একটা ভ্যালু প্রথমে সংযোজন করা হইলে তা প্রথমেই বিয়োজন হবে। এখন একটু রিয়েল লাইফ উদাহরণ দেওয়া যাক -

- রিয়েল লাইফ উদাহরণ -

গত ব্লগে আপনার মামার মেয়ের তো বিয়ে হয়ে গেলো কিন্তু সেই বিয়েতে আপনি থালা বিতরন ছাড়া আর কিছুই করতে পারলেন নাহ । কিন্তু আপনি কি হাল ছেড়ে দেওয়ার মতো মানুষ ? নাহ অবশ্যই নাহ ।

হ্যাঁ আপনি আপনার মামাতো বোন কে পান নাই তাতে কি হয়েছে পৃথিবীতে কি মেয়ের অভাব নাকি ? তাই আপনিও আপনার মামার মেয়ের মতো বিয়ে করে ফেললেন । এখন আপনার মামাতো বোন কে তো দেখাতে হবে নাকি ? তাই আপনি প্ল্যান করলেন যে, হানিমুনে যাবেন দেশের কোথাও।

এই সুবাধে আপনি আগামিকালের টিকিট আজকেই বুক করতে গেলেন কিন্তু ওমা এ কি!

টিকিট কাউন্টারে তো অনেক লোক লাইন হয়ে দাঁড়িয়ে আছে । এবং তারা সিরিয়াল মোতাবেক একজনের পর একজন টিকিট নিচ্ছে । এখন আপনার সিরিয়াল ধরেন ১৮ নম্বর। তাহলে যখন আপনার সিরিয়াল আসবে তখনই আপনি টিকিট নিতে পারবেন ।

এখন আপনি মনে মনে ভাবতেছেন যে, ইস! যদি খানিকটা আগে আসতে পারতাম তাহলে আগেই যাইতাম । আসলেই, আগে আসলে আগেই যাইতে পারতেন । কিন্তু কি আর করার ।


 

আশা করি আপনি এখানে Queue ডাটা-স্ট্রাকচারের আচরণ ধরতে পারছেন । যদি এখনও আপনার খাটাস ব্রেইনে কিছু নাহ ঢুকে থাকে তাহলে চলেন আরেকটু বোঝা-বুঝি সেরে ফেলা যাক -

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

এভাবে পর পর ৬ জন মানুষ তাদের সিরিয়াল মেইন্টেইন করে টিকিট নিয়ে সেখান থেকে চলে যাবে। তাহলে বিষয়টা দাড়ালো যে, প্রথম যে মানুষটা লাইনে ইন হইলো সেই মানুষটাই প্রথমেই টিকিট নিয়ে লাইন থেকে আউট হয়ে গেলো । তাহলে কিন্তু এখানেও FIFO প্যাঁরাডাইম(paradigm) মেনে চললো অর্থাৎ - First In First Out।

- Common operations on Queue -

যে কোনো ল্যাংগুয়েজেই হোক নাহ কেনো Queue ইমপ্লিমেন্ট(implement) করার সময় মাস্ট(must) আমাদেরকে দুইটা মেথড তৈরি করতেই হবে-

  1. enqueue - Queue এ আইটেম সংযোজন ।
  2. dequeue - Queue থেকে আইটেম বিয়োজন ।

এইখানে মেথডস নেইম যে enqueue এবং dequeue ই হবে সেরকম বাধা-ধরা কোনো নিয়ম নেই । আপনি চাইলে add , remove বা আপনার সুবিধা-মতো যেকোনো নেইম দিতে পারেন । তবে এই দুইটা মেথড ছাড়াও Queue এ আমাদের প্রয়োজন মতো অনেক মেথডস তৈরি করতে পারি ।

- Queue এ আমরা যে মেথডস গুলো তৈরি করতে যাচ্ছি -

  1. enqueue() - Queue এ আইটেম সংযোজন ।
  1. dequeue() - Queue থেকে আইটেম বিয়োজন ।
  1. size() - Queue এ আইটেম কতগুলো আছে তা জানতে।
  1. isEmpty() - Queue খালি কি নাহ তা জানতে।

- Implementing a queue in JavaScript -

Queue ইমপ্লিমেন্ট(implement) করতে আমি নেটিভ অ্যারে(array) এবং ক্লাস(class) কে বেছে নিবো । তবে লিঙ্কড-লিস্ট(linked-list) এবং ফাংশন(function) দিয়েও চাইলে করতে পারেন ।

- ক্লাস(class) ডিফাইন -

class Queue{
    // code here
}

- কন্সট্রাক্টর(constructor) তৈরি -

constructor(){
    this.queue = [];
}

এখানে একটি constructor ফাংশন নিয়েছি এবং this.queue নামে একটা প্রোপার্টি নিয়েছি যা মুলত একটা অ্যারেকে হোল্ড করে । এই অ্যারেই মুলত Queue এর আইটেমগুলো কে কনট্রোল করবে ।

- enqueue() method -

এই মেথডের সাহায্যে কোনো আইটেম Queue এর প্রথমে সংযোজন করা যাবে ।

enqueue(element) {
    this.queue.unshift(element)
  }

অ্যারের unshift মেথডের সাহায্য নেওয়া হয়েছে যা এলিমেন্টকে খুব সহজেই Queue এর প্রথমে যুক্ত করে দিবে ।

- dequeue() method -

  dequeue() {
    if (this.queue.length) {
      return this.queue.pop();
    } else {
      return "(dequeue failed), No item in queue!";
    }
  }

এখানে বলা হয়েছে যে যদি Queue এর লেন্থ শুন্য(0) থেকে বড় হয় তাহলে Queue থেকে শেষের এলিমেন্টকে ডিলিট করে দিবে। শেষের এলিমেন্ট সেইটাই যেইটা Queue এ প্রথমে এড করা হবে । আর বুঝতেই পারছি যে, শুন্য(0) থেকে বড় মানে Queue এ এলিমেন্ট আছে।

আর যদি Queue এ এলিমেন্ট নাহ থাকে তাহলে (dequeue failed), No item in queue! রিটার্ন করবে ।

- size method -

Queue এ কতোগুলো আইটেম আছে তা এই সাইজ(size) মেথড রিটার্ন করবে ।

size() {
    return this.queue.length;
  }

- isEmty method -

Queue খালি কি নাহ তা জানা যাবে isEmty() মেথডের এর সাহায্যে । যদি Queue এ আইটেম থাকে তাহলে false আইটেম নাহ থাকলে true রিটার্ন করবে।

isEmpty() {
  return this.queue.length === 0;
}

- Final Queue -

// implement queue
class Queue {
  constructor() {
    this.queue = [];
  }

  // add item in first position
  enqueue(element) {
    this.queue.unshift(element)
  }

  // remove last item which is the first item
  dequeue() {
    if (this.queue.length) {
      return this.queue.pop();
    } else {
      return "(dequeue failed), No item in queue!";
    }
  }

  // length of queue
  size() {
    return this.queue.length;
  }

  // check if queue is empty
  isEmpty() {
    return this.queue.length === 0;
  }

}

আপনি চাইলে Queue এ প্রয়োজন মতো আরও অনেক মেথড যুক্ত করতে পারেন । এখন আমাদের তৈরি করা Queue টেস্ট করে দেখবো যে সব কিছু ঠিকমতো কাজ করছে কি নাহ ।

- Create a Queue -

// create a queue
const queue = new Queue();

- Add Item To Queue -

queue.enqueue("shakil");
queue.enqueue("torikus");
queue.enqueue("morshed");
queue.enqueue("afifa");

// queue
[ 'afifa', 'morshed', 'torikus', 'shakil' ]

যেহেতু queue এ সর্বপ্রথমে shakil কে সংযোজন করা হয়েছে এখন যদি বিয়োজন করি তাহলে -

- Remove last item which is the first item -


console.log(queue.dequeue()); // shakil

console.log(queue);
// [ 'afifa', 'morshed', 'torikus' ]

যেহেতু queue এ সর্বপ্রথম shakil কে সংযোজন করা হয়েছে তাই dequeue() করার পর shakil কেই প্রথম বিয়োজন করে ফেলছে ।

- Length in Queue -

console.log(queue.size());
// 3

আমরা দেখতে পাইতেছি যে, queue এ তিনটি আইটেম আছে তাই আউটপুট হিসেবে 3 কেই রিটার্ন করা হয়েছে।

- Check if queue is empty -

console.log(queue.isEmty());
// false

যেহেতু, queue এ আইটেম আছে তাই আউটপুট হিসেবে false কেই রিটার্ন করা হয়েছে যদি আইটেম নাহ থাকতো তাহলে true রিটার্ন করতো। আমাদের queue ঠিক-ঠাক মতো কাজ করতেছে।

- শেষের কথা -

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

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

ধন্যবাদ।

Share:

Saturday 29 January 2022

Stack data structure in javascript

 

baburjhuli

হে সুন্দর মানুষজন আসসালামু-আলাইকুম সবাইকে,

কম্পিউটার সাইন্সে কমন এবং বহুল ব্যবহৃত ডাটা-স্ট্রাকচার গুলোর মাঝে Stack একটি । আমরা আজকে এই ডাটা-স্ট্রাকচার সমন্ধে শিখতে যাচ্ছি, Stack কি তা জানার আগে একটু বোঝার চেষ্টা করি যে লিনিয়ার(Linear) ডাটা-স্ট্রাকচার কি ?

- লিনিয়ার(Linear) ডাটা-স্ট্রাকচার কি ?

যেসব ডাটা-স্ট্রাকচারে ডাটা গুলো একটি নির্দিষ্ট সিকুয়েন্সিয়াল(sequential) অর্ডারে(order) থাকে অর্থাৎ ডাটা সমূহ নির্দিষ্ট ভাবে সাজানো গোছানো অবস্থায় রাখা হয় । যেখানে ডাটা সমূহ একটি আরেকটির সাথে কানেক্টেড থাকে এবং খুব দ্রুত বিভিন্ন অপারেশনসমূহ সম্পন্ন করা হয় যেমন - ট্রাভারসিং(Traversing), সার্চিং(Searching) , মারজিং(Merging) ইত্যাদি তাদেরকেই লিনিয়ার(Linear) ডাটা-স্ট্রাকচার বলা হয়।

- Stack কি ?

Stack একটি লিনিয়ার(Linear) ডাটা-স্ট্রাকচার যা LIFO প্যাঁরাডাইম(paradigm) মেনে চলে । LIFO এর পূর্ণরূপ হইলো - Last In First Out অর্থাৎ Stack এ কোনো একটা ভ্যালু শেষে সংযোজন করা হইলে তা প্রথমেই বিয়োজন হবে। এখন একটু রিয়েল লাইফ উদাহরণ দেওয়া যাক -

- রিয়েল লাইফ উদাহরণ -

অনেক স্বপ্ন ছিলো আপনার মামার মেয়েকে বিয়ে করবেন কিন্তু আজ সেই মেয়ের বিয়ে। আমি খুবই দুঃখিত যে বরটা আপনাকে বানাতে পারলাম নাহ । তবে আপনি সেই বিয়েতে একজন ওয়ার্কার যে কিনা মেহমানদের মাঝে থালা(Plate) সার্ভ করার দায়িত্ব পালন করবেন ।

কিছুক্ষণ পর আপনি বেসিন থেকে কয়েকটি করে থালা হাতে নিয়ে আবার তা মেহমানদের মাঝে দিয়ে আসতেছেন । আপনি মুলত নাকের জলে চোখের জলে আজ এই কাজটাই পালন করতেছেন।

এইখানে একটা জিনিস খেয়াল করেছেন ? এই যে আপনি বেসিন থেকে থালা একটি একটি করে হাতে নিচ্ছেন এবং তা আবার একটি একটি করে মেহমানদের মাঝে সার্ভ করতেছেন ।

ধরি যে, এইবার আপনি ৮টি থালা বেসিন থেকে হাতে নিয়েছেন । যখন ৮টি থালার ১ম টি হাতে নিয়েছেন তখন আপনার হাতে থালা একটি । তারপর যখন ২ নাম্বার থালা হাতে নিলেন তখন আপনার হাতে থালা দুইটি এবং প্রথম যে থালাটা হাতে নিয়েছেন সেইটা কিন্তু এখন ২য় থালার নিচে। এভাবে পর্যায়ক্রমে আপনি ৮ টি থালা হাতে নিয়েছেন ।

তাহলে সবশেষে যে থালাটা হাতে নিলেন অর্থাৎ ৮ নাম্বার থালা সেইটা কিন্তু এখন সবার ওপরে । এবং প্রথমে যে থালাটা নিয়েছিলেন সেইটা কিন্তু এখন সবার শেষে । তাই নাহ ?


 

এখন আপনি ৮টি থালা মেহমানদের দিতে গেলেন এবং উপরের থালাটা একজনকে দিলেন । আপনি কিন্তু উপরের থালাটা অর্থাৎ ৮ নাম্বার থালাটা একজনকে দিয়ে দিলেন। তার মানে কি ? আপনি সবশেষে যে থালাটা আপনার হাতে নিয়েছিলেন সেই থালাটাই আপনি সর্বপ্রথম একজনকে দিয়ে দিলেন। এইভাবে পর্যায়ক্রমে আপনি সব থালায় মেহমানদের দিয়ে দিলেন ।

তাহলে সারমর্ম এই যে, বেসিন থেকে সর্বশেষে যে থালাটা আপনি হাতে নিয়েছিলেন তা সর্বপ্রথম হাত থেকে সরিয়ে ফেললেন । এবং সর্বপ্রথম যে থালাটা হাতে নিয়েছিলেন তা সর্বশেষে হাত থেকে সরিয়ে ফেললেন।

এখানেও কিন্তু LIFO প্যাঁরাডাইম(paradigm) মেনে চললো অর্থাৎ - Last In First Out , শেষে যে থালাটা হাতে ইন করলেন প্রথেমেই সেইটাকে আউট করে দিলেন । আশা করি এখন আপনি Stack সম্পর্কে Theoretical একটা ধারণা পেলেন।

আপনার মনের কোথাও যদি সুর-সুরি দিয়ে উঠে যে, Stack জাভাস্ক্রিপ্টে বিল্ট-ইন ডাটা-স্ট্রাকচার কি না ? তাহলে উত্তর হবে - নাহ । এটি অ্যারে, অব্জেক্ট বা অন্য ডাটা-স্ট্রাকচারের মতো বিল্ট-ইন নাহ ।

যেহেতু আমরা মোটামোটি বুঝি যে, Stack ডাটা-স্ট্রাকচার কি তাহলে চলুন এখন আমরা খুব সহজেই এইটা কে ইমপ্লিমেন্ট(implement) অর্থাৎ তৈরি করে ফেলি ।

- Stack  ডাটা-স্ট্রাকচার ইমপ্লিমেন্ট(implement) করার আগে -

যে কোনো ল্যাংগুয়েজেই হোক নাহ কেনো Stack ইমপ্লিমেন্ট(implement) করার সময় মাস্ট(must) আমাদেরকে দুইটা মেথড তৈরি করতেই হবে -

১। push - stack এ আইটেম সংযোজন ।

২। pop - stack থেকে আইটেম বিয়োজন ।

এইখানে মেথডস নেইম যে push এবং pop ই হবে সেরকম বাধা-ধরা কোনো নিয়ম নেই । আপনি চাইলে add , remove বা আপনার সুবিধা-মতো যেকোনো নেইম দিতে পারেন ।

তবে এই দুইটা মেথড ছাড়াও Stack এ আমাদের প্রয়োজন মতো অনেক মেথডস তৈরি করতে পারি ।

- Stack  এ আমরা যে মেথডস গুলো তৈরি করতে যাচ্ছি -

1। push - stack এ আইটেম সংযোজন ।

2। pop - stack থেকে আইটেম বিয়োজন ।

3। size - stack এ আইটেম কতগুলো আছে তা জানতে।

4। isEmpty - stack খালি কি নাহ তা জানতে।

- Stack  ইমপ্লিমেন্ট(implement) -

Stack ইমপ্লিমেন্ট(implement) করতে আমি নেটিভ অ্যারে(array) এবং ক্লাস(class) কে বেছে নিবো । তবে লিঙ্কড-লিস্ট(linked-list) এবং ফাংশন(function) দিয়েও চাইলে করতে পারেন ।

- ক্লাস(class) ডিফাইন -

class Stack{
    // code here
}
 

- কন্সট্রাক্টর(constructor) তৈরি -

constructor(){
    this.stack = [];
}
 

এখানে একটি constructor ফাংশন নিয়েছি এবং this.stack নামে একটা প্রোপার্টি নিয়েছি যা মুলত একটা অ্যারেকে হোল্ড করে । এই অ্যারেই মুলত Stack এর আইটেমগুলো কে কনট্রোল করবে ।

- push method -

 push(element) {
    this.stack.push(element)
  }

অ্যারের push মেথডের সাহায্য নেওয়া হয়েছে যা এলিমেন্টকে খুব সহজেই Stack এর শেষে যুক্ত করে দিবে ।

- pop method -

  pop() {
    if (this.stack.length) {
      return this.stack.pop();
    } else {
      return "(pop failed), No item in stack!";
    }
  }

এখানে বলা হয়েছে যে যদি Stack এর লেন্থ শুন্য(0) থেকে বড় হয় তাহলে Stack থেকে শেষের এলিমেন্টকে ডিলিট করে দিবে। শুন্য(0) থেকে বড় মানে Stack এ এলিমেন্ট আছে।

আর যদি Stack এ এলিমেন্ট নাহ থাকে তাহলে (pop failed), No item in stack! রিটার্ন করবে ।

- size method -

  size() {
    return this.stack.length;
  }

Stack এ কতোগুলো আইটেম আছে তা এই সাইজ(size) মেথড রিটার্ন করবে ।

- isEmty method -

isEmpty() {
  return this.stack.length === 0;
}

stack খালি কি নাহ তা জানা যাবে isEmty এর সাহায্যে । যদি stack এ আইটেম থাকে তাহলে false আইটেম নাহ থাকলে true রিটার্ন করবে।

- Final Stack -

class Stack {
  constructor() {
    this.stack = [];
  }

  // push item to stack
  push(item) {
    this.stack.push(item);
  }

  // remove last item
  pop() {
    if (this.stack.length) {
      return this.stack.pop();
    } else {
      return "(pop failed), No item in stack!";
    }
  }

  // get stack length
  size() {
    return this.stack.length;
  }

  // check if stack is empty
  isEmpty() {
    return this.stack.length === 0;
  }
}

আপনি চাইলে stack এ প্রয়োজন মতো আরও অনেক মেথড যুক্ত করতে পারেন । এখন আমাদের তৈরি করা stack টেস্ট করে দেখবো যে সব কিছু ঠিকমতো কাজ করছে কি নাহ ।

- Create a Stack -

const stack = new Stack();

- Add Item To Stack -

stack.push('torikus');
stack.push('fahim');
stack.push('afifa');

// ['torikus', 'fahim', 'afifa']

stack এ সবশেষে afifa কে সংযোজন করা হয়েছে এখন যদি বিয়োজন করি তাহলে -

- Remove Last Item To Stack -

console.log(stack.pop()); // 'afifa'
// [ 'torikus', 'fahim' ]

যেহেতু stack এ সবশেষে afifa কে সংযোজন করা হয়েছে তাই pop() করার পর afifa কেই প্রথম বিয়োজন করে ফেলছে ।

- Length In Stack -

console.log(stack.size()); // 2

যেহেতু, stack এ দুইটি আইটেম আছে তাই আউটপুট হিসেবে 2 কেই রিটার্ন করা হয়েছে।

- Check If Stack Is Empty -

console.log(stack.isEmty());
// false

যেহেতু, stack এ আইটেম আছে তাই আউটপুট হিসেবে false কেই রিটার্ন করা হয়েছে যদি আইটেম নাহ থাকতো তাহলে true রিটার্ন করতো।

আমাদের stack ঠিক-ঠাক মতো কাজ করতেছে। আশা করি আপনি পুরো আর্টিকেল বুঝতে পেরেছেন ।

- শেষের কথা -

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

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

 

Share: