Professional Documents
Culture Documents
Sorting
Sorting
Jarif Rahman
1
সূ চীপতৰ্
1 Bubble Sort 3
2 Merge Sort 3
3 Counting Sort 7
4 C++ functions 8
4.1 std::sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2
Compatitive Programming এর সবেচেয় েবিসক িবষয় বস্তুর একটা হেলা সিটর্ং। সিটর্ং Compatitive
Programming অহরহ লােগ। সিটর্ং এর মুল িবষয় হেলা একটা অয্ােরেক েকােনা এক কৰ্েম সাজােনা বা
সটর্ করা। সিটর্ং এর জনয্ অেনক অয্ালগিরদম আেছ। এর মেধয্ গুরুতব্পুণর্ কেয়কটা েদখােনা হেলা। আমরা
আপাতত শুধু েছাট েথেক বড় সটর্ করা িনেয়ই মাথা ঘামােবা।
1 Bubble Sort
Bubble Sort েবাধায় সবেচেয় সহজ সিটর্ং অয্ালগিরদম। এিট O(n2 ) এ কাজ কের। ধর n সাইজ এর
একটা অয্াের a েক সটর্ করেত চাই। আমরা অয্ােরটার ওপর n বার ইটােরট করেবা। পৰ্েতয্কবার যখন
a[i] > a[i + 1] হেব আমরা এেলেমন্ট দুইটােক swap কের িদেবা। পৰ্থম ইটােরশেনর পর সবেচেয় বড়
সংখয্া তার সিঠক জায়াগায় আসেব, িদব্তীয় ইটােরশেনর পর িদব্তীয় সবেচেয় বড় সংখয্া তার সিঠক জায়াগায়
আসেব, · · ·, n টা ইটােরশেনর পের সব গুলা সংখয্া িনেজর সিঠক জায়গায় চেল আসেব।
2 Merge Sort
Merge Sort অয্ালগিরদম সম্পূ ণর্ ভােব megre নােমর অনয্ এক এলগিরদেমর ওপর িনভর্রশীল। তাই
merge sort িশখার আেগ আমােদর merge অয্ালগিরদম িশখা লাগেব।
Merge অয্ালগিরদম দুইটা sorted অয্ােরেক ইনপুট িহেসেব েনয়, আর ওই দুটা অয্ােরেক combine
কের একটা নতুন sorted অয্াের আউটপুট িহেসেব েদয়। েযমন: ইনপুট [1, 2, 4, 10, 13] আর [2, 3, 5]
হেল আউটপুট হেব [1, 2, 2, 3, 4, 5, 10, 13]। Merge অয্ালগিরদম O(n + m) এ কাজ কের েযখােন n, m
যথাকৰ্েম অয্াের দুইটার সাইজ।
ধেরা আমােদর দুইটা অয্াের a আর b েদওয়া আেছ। আমরা দুইটােক merge কের c বানােত চাই। অয্াের
a sorted, অথর্াৎ েযেকােনা i, j(i ≤ j) এর জনয্ ai ≤ aj । তাই a অয্ােরর আেগর সংখয্াগুলা c অয্ােরেতও
আেগ থাকেব, আর পেরর গুলা c অয্ােরেতও পের থাকেব। একই কথা b অয্ােরর জনয্ও সতয্।
এই ফয্াক্টটা বয্াবহার কের merge অয্ালগিরদম কাজ কের। Merge করার জনয্ আমরা দুইটা পেয়ন্টার রা-
খেবা (আসেল সিতয্কােরর পেয়ন্টার না রাখেলও হেব, ইনেডক্স িদেয়ও কাজ চেল যােব, implementation
েদখ)। ধর পেয়ন্টার দুইটা i আর j । শুরুেত i = j = 0। যিদ ai ≤ bj হয় আমরা c অয্ােরেত ai add
িদব, এবং i এর মান এক বাড়ায় িদব। ai > bj হেল c অয্ােরেত bj add কের িদব, এবং j এর মান এক
বাড়ায় িদব। িনেচর উদাহরণ েদখেলই বুঝেত পারবা এটা েকন কাজ কের।
3
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2], i = 1, j = 0 (ai ≤ bj )
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2, 2], i = 2, j = 0 (ai > bj )
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2, 2, 3], i = 2, j = 1 (ai > bj )
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2, 2, 3, 4], i = 2, j = 2 (ai ≤ bj )
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2, 2, 3, 4, 5], i = 3, j = 2 (ai > bj )
• a = [1, 2, 4, 10, 13], b = [2, 3, 5], c = [1, 2, 2, 3, 4, 5, 10], i = 3, j = 3 > |b| (10 is the only
option)
Merge Sort একটা সিটর্ং অয্ালগিরদম েযটা একটা অয্ােরেক O(n log n) এ সটর্ করেত পাের। এটা
recursively কাজ কের। ধর আমরা merge_sort(a, l, r) নােমর একটা ফাংকশান বানােবা েযটা
অয্াের a েক a[l] েথেক a[r] পযর্ন্ত sort করেব (পুরাটা sort করেত আমরা
merge_sort(a, 0, a.size()-1) call করব)। merge_sort ফাংকশানটা এভােব কাজ করেব:
• যিদ l == r হয় তাহেল এই range এ শুধু একটা সংখয্া আেছ। একটা সংখয্া িনেজই sorted।
তাই আর িকছু করা লাগেব না।
4
• যিদ l != r হয় তাহেল আমরা এই range েক দুইটা সমানভােগ ভাগ করব। যিদ সমান ভােগ
ভাগ না করা যায় তাহেল এক এেলেমন্ট কম েবিশ করা যােব (েযমন 7 টা এেলেমন্ট থাকেল পৰ্থম
ভােগ 4 আর িদব্তীয় ভােগ 3 এেলেমন্ট েদয়া যােব)। আমরা এই দুই ভােগর ওপর merge_sort
call কের এেদরেক সটর্ কের িনব (আবার মেন কিরেয় েদই Merge Sort িকন্তু recursively কাজ
কের)। তারপর এই দুইটা range েক merge অয্ালগিরদম দব্ারা merge কের িনব।
• Simple :D
এখােন [7, 4, 6, 2, 7] অয্ােরর ওপর merge sort করার একটা gif পাওয়া যােব। সবাই এটা েদেখ আেসা।
কারণ আিম পৰ্ায় sure েয শুধু মাতৰ্ কথা িদেয় megre sort বুঝান সম্ভব হেব না।
gif এ েযই িটৰ্ টা েদখােনা হেয়েছ েসটােক বেল merge sort tree।
েদখ এখােন পৰ্েতয্কটা েলেভল এ অয্ােরটা দুইভােগ ভাগ হেচ্ছ। তাই এই িটৰ্টার height পৰ্ায় log n েযখােন
n হেলা অয্ােরটার উপাদান সংখয্া। পৰ্েতয্ক েলেভল এ আমরা সেবর্াচ্চ n বার merge করব (পৰ্েতয্ক েলেভেল
উপাদানই েতা সেবর্াচ্চ n টা :P)। তাই Merge Sort এর time complexity O(n log n)।
Implementation
5
vector<int> c(a.size()+b.size());
int i = 0, j = 0;
while(i < a.size() || j < b.size()){
if(j == b.size()) c[i+j] = a[i], i++;
else if(i == a.size()) c[i+j] = b[j], j++;
else if(a[i] <= b[j]) c[i+j] = a[i], i++;
else c[i+j] = b[j], j++;
}
return c;
}
int main(){
vector<int> v = {7, 4, 6, 2, 7};
megre_sort(v, 0, 4);
//v = {2, 4, 6, 7, 7}
}
template<typename it>
void merge_sort(it l, it r){
int n = r-l;
if(n <= 1) return;
int md = n/2;
merge_sort(l, l+md);
merge_sort(l+md, r);
typename remove_reference<decltype(*l)>::type* sth
= new typename remove_reference<decltype(*l)>::type[n];
for(int i = 0; i < n; i++) sth[i] = *(l+i);
merge(sth, sth+md, sth+md, sth+n, l); //std::merge
delete[] sth;
}
int main(){
vector<int> v = {7, 4, 6, 2, 7};
merge_sort(v.begin(), v.end()); //v = {2, 4, 6, 7, 7}
array<int, 5> a = {7, 4, 6, 2, 7};
merge_sort(a.begin(), a.end()); //a = {2, 4, 6, 7, 7}
}
এটা আেগর েচেয় কিঠন িকন্তু এটা েবিশ STL-ish, flexible আর fast।
6
3 Counting Sort
আমরা এখন পযর্ন্ত যত সিটর্ং অয্ালগিরদম েদেখিছ সবই comparision sort। আমরা সটর্ করার সময়
েছাট েথেক বড় সটর্ কেরিছলাম। িকন্তু একটু িচন্তা করেলই বুঝেত পারেব আমরা েছাট েথেক বড় বােদ অনয্
েকােনা কৰ্ম ও বয্বহার করেত পারতাম। েযমন: বড় েথেক েছাট, lexographically ইতয্ািদ। Merge
Sort আমেদর শুধু merge ফাংকশানটা একটু পিরবতর্ন করেত হেতা। েযমন দুইটা string েক যখন
compare করা হয় তখন lexographically compare করা হয়। তাই এই েকাডটা
string েক lexographically সটর্ করেব। িকন্তু আমরা যিদ string েক সাইজ অনু যায়ী সটর্ করেত চাই
তাহেল ৭ম লাইেন a[i] <= b[j] এর জায়গায় a[i].size() <= b[j].size() িদেলই হেয়
যােব।
আমরা সিটর্ং এর জনয্ েযেকােনা রকম কৰ্ম বয্বহার করেত পাির যতক্ষণ েসই কৰ্ম িনেচর সতর্টা মােন:
• যিদ ওই কৰ্ম অনু যায়ী a ≤ b হয় এবং b ≤ c হয় তাহেল ওই কৰ্ম অনু যায়ী a ≤ c হেব।
এটা পৰ্মািণত েয েকােনা comparision sorting algorithm O(n log n) এর েচেয় efficient হেত
পাের না।
Counting Sort একটা non-comparision sorting algorithm। এখােন কৰ্ম েযেকােনা হেত পাের
না। সাধারণত আমরা শুধু পুণর্সংখয্ােক েছাট েথেক বড় বা বড় েথেক েছাট সটর্ করেত এটােক বয্বহার
কের থািক। Counting Sort এ শতর্ হেলা ইনপুট অয্ােরর সংখয্াগুলােক েছাট েছাট হওয়া লাগেব। যিদ
ইনপুট অয্ােরেত n টা সংখয্া থােক এবং ইনপুট অয্ােরর সকল সংখয্া 0 েথেক m এর মােঝ হয় তাহেল
এর time complexity হেব O(n + m)।
ধর আমােদর ইনপুট অয্াের a। এবং m সাইেজর নতুন এক অয্াের c বানাব েযখােন ci হেলা a অয্ােরেত
i কয়বার আেছ তার সংখয্ায়। অনয্ ভােব বলেল আমরা c অয্ােরর ci েত a অয্ােরেত i কয়বার আেছ তা
7
count কের রাখব (বুঝাই যােচ্ছ েকেনা এেক Counting Sort বলা হয়)। ধর আমরা a অয্ােরেক সটর্
কের b অয্াের বানােত চািচ্ছ, আমরা b অয্ােরেত c0 টা 0, c1 টা 1, c2 টা 2, · · ·, cm−1 টা m − 1 add
িদব।
েযমন: a = [2, 3, 1, 5, 5, 1, 5] হেল c = [0, 2, 1, 1, 0, 3]। এরপর আমরা b েত 0 টা 0, 2 টা 1, 1 টা 2, 1
টা 3, 0 টা 4 এবং 3 টা 5 add িদব। তাহেল b = [1, 1, 2, 3, 5, 5, 5] হেব।
Implementation
int main(){
vector<int> v = {2, 3, 1, 5, 5, 1, 5};
auto s = counting_sort(v, 6); // s = {1, 1, 2, 3, 5, 5, 5}
}
4 C++ functions
4.1 std::sort
C++ এ std::sort অেনক efficiently implement করা। তাই আমরা সাধারণত ওটাই বয্বহার কের
থািক। std::sort introsort নােমর এক অয্ালগিরদমেক implement কের। introsort ও O(n log n)
এ কাজ কের। িকন্তু এখােন সু িবধার কথা হেলা এর memory complexity O(1) েযখােন Merge Sort
এর memory complexity O(n) কারণ পৰ্েতয্কবার merge করার সময় আমােদর এেলেমন্ট গুলােক
অনয্ অয্ােরেত কিপ করেত হয়। আমরা একই অয্ােরেত merge করেত পাির না। তাই আমরা সাধারণত
std::sort ই বয্বহার কের থািক। Merge Sort েতমন একটা কােজ আেস না। এটা িশখােনা হেয়েছ
শুধু জানার জনয্। িকন্তু কখেনা কখেনা merge sort কােজ আসেত পাের। Custom Comparators এ
েদখেব আমরা েছাট েথেক বড় বােদও অনয্ ফাংকশান বয্বহার করেত পাির। যিদ েকােনা interactive
পৰ্েব্লম এ আমােদর েকােনা এেলেমন্ট েক compare করেত পৰ্েতয্কবার query করা লােগ এবং আমােদর
সীিমত সংখয্ক query থােক তাহেল Merge Sort বয্বহার করাই েবিশ ভােলা হেব। কারণ Merge Sort
িকভােব কাজ কের েসটা েদখেলই বুঝেত পারবা এখােন n(⌈log n⌉ + 1) এর েচেয় েবিশ query করা হেব
না। িকন্তু std::sort এর time complexity O(n log n) হেলও এখােন হালকা constant factor
আেছ। তাই এটােত query এর সংখয্া n log n পার হেয় েযেত পাের।
8
4.2 Custom Comparators
আেগই বলা হেয়েছ েয comparision sorting algorithm এ আমরা বড় েথেক েছাট বােদও অনয্
েকােনা কৰ্ম বয্বহার করেত পারব। C++ std::sort এর default comparator হেলা <। যিদ েকােনা
comparator না বেল েদওয়া হয় তাহেল এেলেমন্টগুলােক < দব্ারা অথর্াৎ েছাট েথেক বড় কৰ্েম সাজােনা
হয়। আমরা std::sort এ custom comparator বয্বহার করেত পাির। Custom comparator হেব
একটা ফাংকশান (বা লয্ামব্ডা হেলও হেব) যার পারািমটার হেব অয্ােরর দুইটা এেলেমন্ট আর ফাংকশান
একটা boolean (true অথবা false) িরটানর্ করেব। যিদ comparator অনু যায়ী পৰ্থমটা েছাট হয় তাহেল
false িরটানর্ করেত হেব। বড় হেল true িরটানর্ করেত হেব। দুইটা সমান হেলও false িরটানর্ করেত
হেব। নাহেল runtime error খােব।
Custom comparator এ লয্ামব্ডা ফাংকশান বয্বহার করাই আমার কােছ েবিশ সু িবধাজনক মেন হয়।
লয্ামব্ডা বয্বহার করেল বার বার ফাংকশান িডেক্লয়ার করা লােগ না।
Custom comparator আেরা িবিভন্ন ভােব বয্বহার করা যায়। েযমন ধর েতামার কােছ একটা অয্াের a
আেছ আর তুিম জানেত চাও a েক সটর্ করার পর iতম এেলেমন্ট কথায় যােব। তুিম এটােক b অয্ােরেত
েসভ কের রাখেত চাও। এটােক এভােব implement করা যােব: