Sparround

Binary Search Tree

BST invariantı: hər node üçün — sol alt-ağacdakı BÜTÜN dəyərlər node-dan kiçik, sağ alt-ağacdakı BÜTÜN dəyərlər node-dan böyükdür.

Diqqət, burada tez-tez səhv edilir: şərt yalnız birbaşa övladlara yox, bütün alt-ağaca aiddir. left.value < node.value yoxlaması kifayət deyil — left alt-ağacında dərində yerləşən bir dəyər də node-dan böyük ola bilməz. BST-ni yoxlayan funksiyanı yazarkən hər node üçün icazə verilən (min, max) diapazonunu aşağı ötürmək lazımdır.

Bu invariant nə verir? Hər müqayisədə axtarış sahəsinin yarısını atırsan — eynilə sıralı massivdə binary search kimi. Fərq odur ki, BST-də əlavə və silmə də O(log n)-dir, sıralı massivdə isə element yerləşdirmək O(n) tələb edir (qalanlarını sürüşdürmək lazımdır).

ƏməliyyatBalanslaşdırılmışDeqradasiya olmuşSıralı massivHash map
AxtarışO(log n)O(n)O(log n)O(1) orta
Əlavə etməO(log n)O(n)O(n)O(1) orta
SilməO(log n)O(n)O(n)O(1) orta
Sıralı çıxışO(n) — inorderO(n)O(n) — hazırdırO(n log n) — sıralamaq lazımdır
Diapazon sorğusuO(log n + k)O(n)O(log n + k)O(n)

Axtarış və əlavə etmə eyni məntiqlə işləyir: root-dan başla, dəyəri node ilə müqayisə et, kiçikdirsə sola, böyükdürsə sağa get. Axtarışda uyğunluq tapanda dayanırsan; əlavə etmədə null yerə çatanda yeni node yaradırsan. Hər ikisi ağacın hündürlüyü qədər addım atır — yəni O(h).

Silmə üç hala bölünür və müsahibədə məhz üçüncüsü soruşulur:

  • Leaf (0 övlad) — sadəcə valideyndəki göstəricini null et.
  • 1 övlad — node-u yeganə övladı ilə əvəzlə. Alt-ağac bütövlükdə yuxarı qalxır, invariant pozulmur.
  • 2 övlad — bu, çətin haldır. Node-u silmək əvəzinə onun inorder successor-u (sağ alt-ağacdakı ən kiçik dəyər) ilə dəyərini əvəzləyirsən, sonra həmin successor-u sağ alt-ağacdan silirsən. Successor-un ən çoxu bir övladı ola bilər (sol övladı yoxdur — o, ən kiçikdir), ona görə ikinci silmə mütləq sadə hallardan biridir və rekursiya dərinləşmir.

Successor əvəzinə inorder predecessor (sol alt-ağacdakı ən böyük dəyər) da işləyir — hər iki seçim invariantı qoruyur.

Niyə pis hal O(n)? BST-nin bütün üstünlüyü h ≈ log n fərziyyəsinə söykənir. Amma adi BST özünü balanslaşdırmır — forma tamamilə əlavə sırasından asılıdır.

Sıralı data əlavə etsən (1, 2, 3, 4, 5...), hər yeni element həmişə sağa gedir və ağac əslində əlaqəli siyahıya çevrilir: h = n, bütün əməliyyatlar O(n). Bu, nəzəri qorxu deyil — real datalar tez-tez sıralı gəlir: ID-lər, timestamp-lar, avtoinkrement açarlar, sıralanmış CSV. Yəni ən təbii input BST-nin ən pis halıdır.

Həll variantları:

  • Özü-balanslaşan ağac — AVL və ya Red-Black. Onlar əlavə/silmə zamanı rotasiya edərək h = O(log n) zəmanətini saxlayır. Növbəti mövzunun mövzusu budur.
  • Datanı qarışdırmaq — əlavə sırasını təsadüfiləşdirsən, gözlənilən hündürlük O(log n) olur. Bu, sadə həlldir, amma zəmanət deyil.
  • Hazır struktur işlətmək — real işdə əl ilə BST yazmırsan: Kotlin-də TreeMap, Dart-da SplayTreeMap, C++-da std::map.

Hash map ilə müqayisə də vacibdir: hash O(1) verir, amma sıra saxlamır. BST-nin varlıq səbəbi sıradır — sıralı iterasiya, diapazon sorğuları, "k-dan kiçik ən böyük açar" (floor/ceiling) kimi əməliyyatlar hash-də mümkün deyil.

İnterview ipucu. İki sual demək olar ki, həmişə gəlir.

Birincisi: "BST-də iki övladlı node-u necə silirsən?" Bu, mövzunun əsl sınağıdır. Güclü cavab: "Node-u fiziki silmirəm — dəyərini inorder successor-la, yəni sağ alt-ağacdakı ən kiçik dəyərlə əvəzləyirəm, sonra həmin successor-u sağ alt-ağacdan silirəm. Successor-un sol övladı ola bilməz, ona görə ikinci silmə mütləq 0 və ya 1 övladlı sadə haldır." Nəyə görə məhz successor — çünki o, node-dan böyük olan ən kiçik dəyərdir, yəni onun yerinə keçməsi invariantı pozmur.

İkincisi: "BST-nin pis halı nədir?" Cavab: sıralı input. Bunu deyəndə mütləq real nümunə əlavə et — avtoinkrement ID və ya timestamp. Sonra həlli göstər: özü-balanslaşan ağac və ya hazır TreeMap.

Ən çox rast gəlinən səhv: BST invariantını yalnız birbaşa övladlara aid etmək. isValidBST yazarkən (min, max) diapazonunu aşağı ötürməsən, kod sadə testlərdə keçir, sonra dərində yerləşən bir node-da uğursuz olur.

📚 Mənbələr və sənədlər