বাইনারি সার্চ ট্রি (Binary Search Tree)
একটা বাইনারি সার্চ ট্রি (BST) হলো এমন একটা বাইনারি ট্রি, যেখানে মাত্র একটা বাড়তি নিয়ম মেনে চলা হয়। আর এই একটা নিয়মই একে এতটা কাজের বানিয়েছে: এই গাছের যেকোনো নোডের জন্য, তার বাঁ দিকের (left) সব ভ্যালু তার চেয়ে ছোট হতে হবে, আর ডান দিকের (right) সব ভ্যালু তার চেয়ে বড় হতে হবে।
এটাকে লাইব্রেরির সুন্দর করে সাজানেন বইয়ের তাকের মতো ভাবতে পারেন। প্রতিটা মোড়ে গিয়ে আপনাকে শুধু একটা সহজ প্রশ্ন করতে হবে: "আমি যেটা খুঁজছি সেটা কি এর চেয়ে ছোট, নাকি বড়?" এই একটা প্রশ্নের কারণেই প্রতি ধাপে আপনার খোঁজার জায়গা অর্ধেক হয়ে যায়।
BST-এর জাদু
এই নিয়মটা শুধু রুটের জন্যই নয়, গাছের প্রতিটা নোডের জন্যই সত্যি হতে হবে। এটা হলো ভেতরে ভেতরে ঘুরে ফিরে আসা একটা গ্যারান্টি।
← → অ্যারো কি (arrow key) ব্যবহার করুন · উপাদানগুলোতে ক্লিক করুন
BST-তে খোঁজা (Search)
খোঁজাখুঁজি সবসময় রুট (Root) থেকে শুরু হয় এবং প্রতিটা নোডে গিয়ে একটাই প্রশ্ন করা হয়: "আমি যেটা খুঁজছি সেটা কি এই নোডের চেয়ে ছোট, বড়, নাকি সমান?"
- সমান — পেয়ে গেছি!
- ছোট — তাহলে বাঁয়ে চলুন।
- বড় — তাহলে ডানে চলুন।
- চলতে চলতে null বা শূন্য জায়গায় চলে আসছি — তার মানে এটা গাছে নেই।
এখানে প্রতিবার তুলনা করার ফলে বাকি থাকা খোঁজার জায়গা প্রায় অর্ধেক হয়ে যায়। একটা ব্যালান্সড বা সুন্দর আকারের গাছে খুঁজতে O(log n) সময় লাগে — অনেকটা সর্ট করা অ্যারেতে বাইনারি সার্চ করার মতো, কিন্তু এখানে সেটা গাছের আকারে হচ্ছে।
BST-তে নতুন কিছু বসানো (Insert)
বসানোর কাজটাও ঠিক খোঁজার রাস্তা ধরেই হাঁটে। আপনি ছোট/বড় ওই একই নিয়ম মেনে গাছের ডাল ধরে নিচে নামতে থাকবেন, যতক্ষণ না একটা খালি জায়গা (empty slot) পাচ্ছেন। খালি জায়গা পেলেই সেখানে নতুন নোডটা বসিয়ে দেবেন। এতে করে BST-এর ওই জাদুকরী নিয়মটা অটোম্যাটিক ঠিক থাকে।
BST থেকে ডিলিট করা
কাউকে মুছে ফেলার ক্ষেত্রে তিন ধরনের পরিস্থিতি তৈরি হতে পারে (ডিপেন্ড করে ওই নোডের কয়টা বাচ্চা আছে তার ওপর):
- বাচ্চাকাচ্চা নেই (Leaf) — জাস্ট মুছে ফেললেই হলো।
- একটা বাচ্চা আছে — মুছে ফেলা নোডের জায়গায় তার ওই বাচ্চাটাকে বসিয়ে দিন।
- দুটো বাচ্চা আছে — এটা একটু ঝামেলার। আপনাকে in-order successor বা ডান দিকের অংশ থেকে সবচেয়ে ছোট ভ্যালুটাকে খুঁজে বের করতে হবে। তারপর সেই ভ্যালুটা এনে আপনার মুছে ফেলার নোডে বসিয়ে দিন, আর সবশেষে ডান দিকের ওই ছোট ভ্যালুর আসল নোডটাকে মুছে ফেলুন।
ইন-অর্ডার ট্রাভার্সাল (In-order) দেয় সর্টেড লিস্ট
BST-এর সবচেয়ে বড় সুপারপাওয়ার হলো: এটাকে ইন-অর্ডার ট্রাভার্স (In-order traversal) (লেফট → রুট → রাইট) করলে সবসময় ছোট থেকে বড় হিসেবে সাজানেন (sorted) লিস্ট পাওয়া যায়। যেমন, {৫, ৩, ৮, ১, ৪} ভ্যালুওয়ালা একটা BST-তে ইন-অর্ডার ঘোরাঘুরি করলে আপনি পাবেন ১, ৩, ৪, ৫, ৮ — একদম পারফেক্টভাবে সাজানেন!
Complexity
BST কখন খারাপ হয়ে যায়?
যদি আপনি একটার পর একটা ডেটা সাজানেন বা সর্টেড অবস্থাতেই গাছে ঢোকাতে থাকেন (যেমন: ১, ২, ৩, ৪, ৫...), তাহলে প্রতিটা নতুন নোড তার আগেরটার ডান দিকে গিয়ে বসতে থাকবে। এর ফলে পুরো গাছটা একটা সোজা লাইন হয়ে যাবে — যেটা আসলে একটা লিংকড লিস্ট ছাড়া আর কিছুই নয়। তখন সব কাজের স্পিড O(log n) থেকে কমে গিয়ে বিরক্তিকর O(n) হয়ে যাবে!
আর ঠিক এই সমস্যা ঠেকানোর জন্যই ব্যালান্সড BST (Balanced BSTs) (যেমন AVL Trees বা Red-Black Trees)-এর জন্ম — এরা এই ধরনের খারাপ অবস্থা থেকে বাঁচার জন্য নিজে নিজেই নিজেদের ডালপালা সাজিয়ে গাছটাকে ব্যালান্সড রাখে।
কোথায় কাজে লাগে?
- এমন জায়গায়, যেখানে ডেটা সবসময় সাজানেন অবস্থায় রাখতে হয়, আবার বারবার নতুন জিনিস ঢোকানো বা মুছে ফেলার দরকার পড়ে।
- রেঞ্জ কুয়েরি করতে (যেমন X থেকে Y-এর মাঝের সব ভ্যালু বের করা)।
- সাজানেন ডেটার ওপর ইন-অর্ডার ইটারেট বা লুপ চালানোর জন্য।
- AVL Trees, Red-Black Trees, এবং Treaps বানানোর মূল ভিত্তি হিসেবে।
ছোট কুইজ
পড়া চালিয়ে যান