কুইক সর্ট (Quick sort) (aka: qsort, Quicksort) একটি দ্রুতগতির সর্টিং অ্যালগরিদম যা C.A.R Hoare আবিষ্কার করেন। এটি একটি ভাগ কর শাসন কর (Divide and Conquer) ঘরনার অ্যালগরিদম যেখানে প্রতিবার আমরা অ্যারেটিকে ২টি ভাগে ভাগ করে সর্ট করবো। আপনারা যদি আগে মার্জ সর্ট নিয়ে দেখে থাকেন তবে বিষয়টি হয়তো ইতোমধ্যে বুঝতে পেরেছেন। (Quick sort Bangla tutorial)
Quick sort Bangla tutorial
কুইক সর্টের (Quick sort) মাধ্যমে সর্ট করতে প্রতিবার আমরা অ্যারের যেকোনো একটি ইলিমেন্টকে এর সর্টেড পজিশনে (Sorted position) বসাবো এবং রিকার্সিভ কলের মাধ্যমে এর দুইপাশের সাব-অ্যারের জন্যও একই কাজ করবো। আমরা যেই ইলিমেন্টকে এর সর্টেড পজিশন এ বসাবো তার বামের সকল ইলিমেন্ট তার ছোট থাকবে এবং ডানের সকল ইলিমেন্ট তার বড় বা সমান থাকবে।
এই “একটি ইলিমেন্ট” বাছাই করার বিভিন্ন পদ্ধতি রয়েছে। তবে আমরা বুঝার এবং ব্যাখার সুবিধার্থে সব সময় শেষের ইলিমেন্টকে এর সর্টেড পজিশনে নিয়ে আসবো। এই ইলিমেন্টটিকে পিভট ইলেমেন্ট (Pivot element) বলা হয়।
এবার আসি সর্টেড পজিশন (Sorted position) কি? ধরেন একটি অ্যারে দেয়া আছে আপনাকে, । আপনাকে বলা হলো 6 এর সর্টেড পজিশন কোনটা? এখন দেখা যাচ্ছে মূল অ্যারেতে 6 এর পজিশন (ইনডেক্স) হলো 7। এবার যদি অ্যারেটিকে সর্ট করা হয় তবে এরকম পাবো। দেখা যাচ্ছে এখানে 6 এর ইনডেক্স 4। তাই এই অ্যারেতে 6 এর সর্টেড পজিশন 4।
আমরা যেই পদ্ধতিতে 6 কে এর সর্টেড পজিশনে নিয়ে যাবো এবং শর্তানুসারে, 6 এর বামের সব ইলিমেন্ট 6 এর ছোট এবং 6 এর ডানের সকল ইলিমেন্ট 6 এর বড় বা সমান হবে সেই পদ্ধতিটির নাম হল পার্টিশনিং (Partitioning)।
কুইক সর্ট শেখার জন্য পার্টিশনিং সবার আগে বুঝতে হবে। এটি বুঝলেই বাকিটুকু এক তুড়িতেই বুঝা সম্ভব।
এবার চলুন আমরা পার্টিশনিং করার অ্যালগরিদমটি দেখে নেই।
Quick sort: অ্যারেকে পার্টিশন করার অ্যালগরিদম – Partitioning
ধরা যাক আমরা কোন অ্যারের থেকে তম ইনডেক্স পর্যন্ত পার্টিশন করবো এবং ধরা যাক আমরা অ্যারেটির ইলিমেন্টকে এর সর্টেড পজিশনে নিয়ে আসবো। পার্টশনিং লজিকটি আসলে খুবই সহজ। শুধু একটু খেয়াল করা লাগবে আসলে কি ঘোটছে ভেতরে।
- দুটি ভ্যারিয়েবল এবং নিতে হবে প্রথমে এবং শুরুতে এবং উভয়ের মান থাকতে হবে।
- যতক্ষণ হয়, ততক্ষন নিচের সাব স্টেপের মত করে কাজ করবো।
- যদি অ্যারের j ইনডেক্স এর ইলিমেন্ট অ্যারের শেষ ইলিমেন্টের চেয়ে ছোটো হয় তবে,
- ইনডেক্স এর ইলিমেন্ট এর সাথে ইনডেক্স এর ইলিমেন্ট এর swap করবো।
- এর মান 1 বাড়াবো।
- এর মান 1 বাড়াবো।
- যদি অ্যারের j ইনডেক্স এর ইলিমেন্ট অ্যারের শেষ ইলিমেন্টের চেয়ে ছোটো হয় তবে,
- লুপের শেষ অ্যারের এবং ইলিমেন্ট এর swap করবো।
- এর মান পিভট ইনডেক্স হিসেবে রিটার্ন করবো।
এখন আসলে কি ঘটল? এখানে প্রথম স্টেপ এ লক্ষ করলে দেখবেন আমরা দুইটি ভ্যারিয়েবল বা চলক নিয়েছি এবং উভয়কেই শূন্যতে সেট করে রেখেছি। তারপর একটি লুপ (while) ব্যবহার করেছি যেটি এর এর থেকে যতক্ষণ ছোট থাকবে, ততক্ষন চলবে। লুপের ভেতরে (Sub-step 2/1) আমরা একটি কন্ডিশন (if) ব্যবহার করেছি এবং এখান থেকেই প্রধান পার্টিশনিং লজিক কাজ করছে।
যদি ভাল করে লক্ষ করেন তবে দেখবেন যে কখনও এর থেকে বড় হতে পারবে না। কারন এর মান বাড়বে তখনি যখন স্টেপ ২ এর সাব-স্টেপ ১ এর শর্ত পূরণ হবে। কিন্তু এর মান সব সময় বাড়বে।
এখন নিচের ভিজুয়ালাইজেশনটি দেখি আমরা। তারপর আরও ব্যাখ্যা করবো প্রসেসটি।
Quick sort visualization with Bangla explanation
উপরের ভিডিওটিতে যদি লক্ষ করেন তবে দেখতে পাবেন যে, এবং এর মাঝে সবসময় এর বড় বা সমান থাকবে। এবং শর্ততে সব সময় এমন জায়গায় থাকবে যেখানে তম ইলিমেন্ট অ্যারের শেষ ইলিমেন্ট এর থেকে বড় হবে। এবং লুপের সবার শেষ ধাপে যাকে নির্দেশ করবে সে অবশ্যই অ্যারের শেষ ইলিমেন্ট এর সমান অথবা বড় হবে কারণ অ্যারের শেষ পর্যন্ত গিয়েছে এবং এর মধ্যে অ্যারের শেষ ইলিমেন্ট থেকে ছোট একটি ইলিমেন্ট পেলেও তা swap করে এর মান বাড়িয়ে নিয়েছে। তাই আমরা লুপ থেকে বের হয়ে swap করার মাধ্যমে শেষ ইলিমেন্টকে (Pivot element) তার সর্টেড পজিশনে রাখি।
উপরের অ্যালগরিদমটিকে int partition(int l,int r,int arr[]) ফাংশনে ইমপ্লিমেন্ট করা হয়েছে।
1 2 3 4 5 6 7 8 9 10 11 12 | int partition(int l,int r,int arr[]){ int i=l,j=l; while(j<r){ if(arr[j]<arr[r]){ // যদি arr[j], arr এর শেষ ইলিমেন্ট arr[r] এর ছোট হয় swap(arr[i],arr[j]); //arr[i] এবং arr[j] কে swap করেছি i++; //i এর মান বড়িয়েছি } j++; //j এর মান বাড়িয়েছি } swap(arr[i],arr[r]);// শেষে পিভট ইলিমেন্ট কে নিজ জায়গায় নিয়ে এসেছি return i; //পিভট ইনডেক্স রিটার্ন করেছি। } |
যেহেতু আগেই বলেছি, কুইক সর্ট একটি ভাগ কর শাসন কর বা ডিভাইড এন্ড কোনকোয়ার অ্যালগরিদম, তাই আমাদের এর মান টি লাগবে অ্যারেটিকে ভাগ করার জন্য। কারন অ্যারের মধ্যে ইনডেক্স এ যে ইলিমেন্ট রয়েছে (swap করার পর) তা তার সর্টেড পজিশনে রয়েছে। শুধু তার আগের এবং পরের সাব-অ্যারেকে সর্ট করা লাগবে এখন।
কুইক সর্ট অ্যালগরিদম (Quick sort algorithm in Bangla)
এতক্ষন আমরা পার্টিশন বুঝেছি। এখন আমরা পুরোপুরি প্রস্তুত কুইক সর্ট বুঝার জন্য। আমরা একটি ফাংশন নিলাম void qsort(int l,int r,int arr[]) নামে। এখানে এবং যথাক্রমে অ্যারে/সাব-অ্যারের বাম এবং ডান ইনডেক্স নির্দেশ করে। এখন নিচ থেকে আমরা কুইক সর্টের কোডটি দেখে নিই।
Quick sort C++ implementation
1 2 3 4 5 6 | void qsort(int l,int r,int arr[]){ if(l>r) return; int p=partition(l,r,arr); //পার্টিশন করার মাধ্যমে পিভট ইনডেক্স খুজে বের করলাম qsort(l,p-1,arr); //রিকার্সিভ ভাবে পিভট এর বামপাশের সাব-অ্যারেকে সর্ট করবো। qsort(p+1,r,arr); //রিকার্সিভ ভাবে পিভট এর ডানপাশের সাব-অ্যারেকে সর্ট করবো। } |
উপরের কোডের দিকে তাকান। খুবই সহজ কোড। প্রথমেই আমরা বেস কেস বিষয়ে ভেবেছি। যদি হয়, এটা সম্ভব না। তাই আমরা রিকার্শন থামাবো।
নয়তো আমরা partition() ফাংশন কল করার মাধ্যমে অ্যারের পর্যন্ত পার্টিশন করবো যেখানে ইলিমেন্টকে আমরা পিভট ইলিমেন্ট হিসেবে বিবেচনা করছি। পার্টিশন হয়ে যাবার পর আমরা জানি হলো পিভট ইলিমেন্ট এর সর্টেড পজিশন, তাই আমরা রিকার্সিভ ভাবে বাম ( এবং ডান সাব-অ্যারেতে একই প্রসেস করে সাব-অ্যারের পিভট ইলিমেন্ট বছাই করবো এবং তাকে তার সর্টেড পজিশনে নিয়ে যাবো। এতে করে একসময় অ্যারেটি সর্ট হয়ে যাবে।
সুতরাং কুইক সর্ট অ্যালগোরিদমটি হলো,
- যদি হয়ে যায় তবে থামতে হবে। কারণ , থেকে বড় হতে পারে না।
- অ্যারের ইলিমেন্টকে (Pivot element) পার্টিশনিং এর মাধ্যমে সর্টেড পজিশনে নিয়ে আসি।
- রিকার্সিভ ভাবে পিভট পজিশন বা এর বাম সাব-অ্যারেকে সর্ট করি।
- রিকার্সিভ ভাবে পিভট পজিশন বা এর ডান সাব-অ্যারেকে সর্ট করি।
আরও পরুন এখানে
কুইক সর্ট অ্যালগরিদম কমপ্লেক্সিটি
কুইক সর্টের বেস্ট কেস এবং এভারেজ কেস টাইম কমপ্লেক্সিটি হলো , কিন্তু বাজে কেস বা Worst case টাইম কমপ্লেক্সইটি । আমরা থেকে এ নামতে পারি। এই উত্তরটি পরুন।
কুইক সর্টের worst case স্পেস কমপ্লেক্সিটি ।
কুইক সর্ট নাকি মার্জ সর্ট (Quick sort vs Merge sort)?
মার্জ সর্টের টাইম কমপ্লেক্সিটি সব সময় কিন্তু কুইক সর্টের (Quick sort) টাইম কমপ্লেক্সিটি থেকে এর মধ্যে থাকে।
কখন কুইক সর্ট ব্যবহার করবোঃ ক্ষেত্র বিশেষে কুইক সর্ট মার্জ সর্ট থেকে ভালো পারফর্ম করে। যেমন যখন ডাটাসেট রেন্ডম থাকে ,আগে থেকেই সর্টেড (ASC বা DESC) না থাকে, এবং ইলিমেন্টের পুনরাবৃত্তি কম থাকে।
কখন মার্জ সর্ট ব্যবহার করবোঃ রেন্ডম ডাটাসেটে মার্জ সর্ট কুইক সর্টের থেকে একটু বেশি সময় নেয়। কিন্তু যখন আপনার ভরসা করার মত একটি অ্যালগরিদম চাই যে যেকোনো ডাটা সাইজে ভালো পারফরমেন্স করে, তখন মার্জ সর্ট উত্তম।
কুইক সর্ট: Full Quick sort code all together – with Bangla explanation
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | #include <iostream> using namespace std; int partition(int l,int r,int arr[]){ int i=l,j=l; while(j<r){ if(arr[j]<arr[r]){ // যদি arr[j], arr এর শেষ ইলিমেন্ট arr[r] এর ছোট হয় swap(arr[i],arr[j]); //arr[i] এবং arr[j] কে swap করেছি i++; //i এর মান বড়িয়েছি } j++; //j এর মান বাড়িয়েছি } swap(arr[i],arr[r]);// শেষে পিভট ইলিমেন্ট কে নিজ জায়গায় নিয়ে এসেছি return i; //পিভট ইনডেক্স রিটার্ন করেছি। } void qsort(int l,int r,int arr[]){ if(l>r) return; int p=partition(l,r,arr); //পার্টিশন করার মাধ্যমে পিভট ইনডেক্স খুজে বের করলাম qsort(l,p-1,arr); //রিকার্সিভ ভাবে পিভট এর বামপাশের সাব-অ্যারেকে সর্ট করবো। qsort(p+1,r,arr); //রিকার্সিভ ভাবে পিভট এর ডানপাশের সাব-অ্যারেকে সর্ট করবো। } int main(){ int arr[]={2,2,4,5,6,7,8,9}; qsort(0,7,arr); for(auto a:arr) cout<<a<<" "; return 0; } |
তো আজকে এই পর্যন্তই। বুঝতে সমস্যা হলে কমেন্ট বক্স আছেই। তা নহলে যেকোনো ভাবে যোগাযোগ কইরেন। #happy_coding.
Animation ta khub helpful silo bro..Keep it up vaiya. We are grateful to you..
ধন্যবাদ আপনাকে ❤️, জেনে আসলেই খুব ভালো লাগলো।
ভাইয়া আপনার সাথে কিভাবে যোগাযোগ করবো, যদি বলতেন
mail: me.sharif.hasan@gmail.com