18 β Balanslangan daraxtlar (AVL, Red-Black, B-tree)¶
β¬ οΈ Oldingi: 17 β Binar qidiruv daraxti (BST) Β· π README Β· Keyingi: 19 β Heap va Priority Queue β‘οΈ
Bu bobda: Oddiy binar qidiruv daraxti (BST) qulay, lekin xavfli β kalitlar tartib bilan kelsa, u "tayoq"ka aylanib, barcha amal
O(n)bo'lib qoladi. Yechim β daraxtni avtomatik balanslangan tutish, ya'ni balandlikni har doimO(log n)darajada saqlash. Biz balanslashning asosiy vositasi bo'lgan aylanish (rotation)ni, so'ng uchta klassik balanslangan struktura β AVL daraxt, Red-Black daraxt va B-tree / B+ treeni o'rganamiz. AVL ni Python'da to'liq yozib, balandligi haqiqatanO(log n)ekanini empirik ko'rsatamiz.Halollik / Eslatma: Aylanish
O(1)ekani, AVL balandligiβ€ 1.44Β·logβ(n)chegarasi, Red-Black "eng uzun yo'l β€ 2Γ eng qisqa" kafolati va B-tree balandligiO(log_t n)ekani β barchasi matematik aniq, isbotlangan natijalar. Bob konseptual jihatdan og'ir: Red-Black va B-tree'ning to'liq implementatsiyasi juda katta (o'chirishda o'nlab hollar), shuning uchun ularning g'oyasi va kafolatini tushuntiramiz, amaliy to'liq kodni esa AVL misolida beramiz. Python kodi haqiqatan ishga tushirilgan: balandlik raqamlari (3, 12, 16, 20) β kod chiqargan haqiqiy qiymatlar.
Eslatma: oddiy BST nimadan aziyat chekadi¶
17-bobda ko'rdikki, binar qidiruv daraxtida qidiruv, qo'shish va o'chirish β hammasi ildizdan bargacha bitta yo'l bo'ylab yuradi. Demak ularning narxi daraxtning balandligiga teng: O(h).
Agar daraxt "chiroyli", ya'ni keng yoyilgan bo'lsa, h β logβ(n) va har amal O(log n) β ajoyib. Lekin BST shaklini kiruvchi ma'lumotlar tartibi belgilaydi, va biz buni boshqarmaymiz. Eng yomon holat: kalitlar o'sib boruvchi tartibda keladi β 10, 20, 30, 40, β¦. Har bir yangi kalit eng o'ngdagi tugunning o'ng farzandi bo'ladi, daraxt o'ngga egiladi va bog'langan ro'yxatga aylanadi:
Bunday "tayoq" (skewed tree) balandligi h = n β 1, demak qidiruv O(n) β biz daraxtdan kutgan barcha tezlik yo'qoladi.
Diqqat: Bu nazariy ehtimollik emas. Real hayotda ma'lumotlar ko'pincha tartiblangan keladi (ID lar, sanalar, alifbo bo'yicha import). Demak oddiy BST'ga ishonib bo'lmaydi β kafolat kerak.
Yechim g'oyasi. Har bir qo'shish/o'chirishdan keyin daraxtni ozgina "tuzatib", balandligini majburan O(log n) da ushlab turamiz. Bu o'z-o'zini balanslaydigan (self-balancing) daraxt deyiladi. Tuzatish narxi ham O(log n), demak hech narsa yo'qotmaymiz β aksincha, eng yomon holat kafolatini qo'lga kiritamiz.
Balans nima degani¶
"Balanslangan" so'zining intuitiv ma'nosi: hech bir shoxcha boshqalaridan haddan tashqari uzun bo'lmasin. Agar har tugunda chap va o'ng qism-daraxtlar balandligi bir-biridan juda farq qilmasa, daraxt yaproqlari taxminan bir tekisda joylashadi.
Formal bog'lanish (nega balans O(log n) beradi): balandligi h bo'lgan daraxtda ko'pi bilan 2^(h+1) β 1 ta tugun bo'ladi. Demak n β€ 2^(h+1) β 1, undan:
Ya'ni n ta tugunni saqlash uchun balandlik hech bo'lmaganda logβ(n) atrofida bo'lishi shart β bundan past tusha olmaymiz. Balanslangan daraxtning butun maqsadi β balandlikni shu mumkin bo'lgan eng kichik qiymat atrofida, ya'ni O(log n) da ushlab turish. Buni uddalasak, barcha amal O(log n) kafolatlanadi.
Turli balanslangan strukturalar "juda farq qilmasin" shartini turlicha qattiqlik bilan qo'yadi:
- AVL: juda qat'iy β har tugunda balandlik farqi ko'pi bilan 1.
- Red-Black: bo'shroq β eng uzun yo'l eng qisqasidan ko'pi bilan 2 barobar uzun.
- B-tree: barcha barglar aynan bir chuqurlikda (mukammal balandlik balansi), lekin tugunda ko'p kalit bo'ladi.
Aylanish (rotation) β asosiy vosita¶
Balanslashning yuragi β aylanish. Bu daraxtning shaklini o'zgartiradigan, lekin in-order tartibni (ya'ni BST xossasini) buzmaydigan lokal operatsiya. Faqat bir nechta ko'rsatkichni qayta ulaydi, shuning uchun narxi O(1).
Tasavvur qiling: x tuguni o'ng tomonga egilgan (o'ng farzandi y og'ir). Biz y ni yuqoriga ko'tarib, x ni uning chap farzandi qilamiz β bu chapga aylanish (left rotation):
Diagrammada e'tibor bering: aylanishdan oldin ham, keyin ham in-order o'qish bir xil β A, x, B, y, C. Faqat kim ildiz ekani va balandlik o'zgardi. Ko'rsatkich mexanikasi (chapga aylanish, x atrofida):
y = x.right # ko'tariladigan tugun
x.right = y.left # y ning chap qism-daraxti (B) x ning o'ngiga ko'chadi
y.left = x # x endi y ning chap farzandi
# yangi ildiz = y
Nega BST buzilmaydi (isbot eskizi). Aylanishdan oldin tartib A < x < B < y < C edi (chunki A β x ning chap qism-daraxti, B β y ning chapi, C β y ning o'ngi). Aylanishdan keyin: A hali ham x ning chapida, B endi x ning o'ngida (x < B), va butun x-qism-daraxt y ning chapida (< y), C esa y ning o'ngida. Demak A < x < B < y < C aynan saqlanadi. β
O'ngga aylanish (right rotation) β buning oynadagi aksi: chap farzand x ni ko'tarib, y ni uning o'ng farzandi qilamiz. Ikkala aylanish ham faqat 3 ta ko'rsatkichni o'zgartiradi, demak O(1), va balandlikni 1 ga kamaytirishi mumkin β balanslashning aniq quroli shu.
Eslatma: In-order traversal (16-bob) β bu yerda asosiy invariant. "Balanslash to'g'rimi?" degan savolga javob: agar in-order saralangan ketma-ketlik o'zgarmasa, daraxt hali ham to'g'ri BST. Aylanish aynan shu xossani saqlaydi.
AVL daraxt β qat'iy balans¶
AVL daraxt (1962, Adelson-Velsky va Landis β nomi shulardan) β tarixdagi birinchi o'z-o'zini balanslaydigan BST. G'oyasi sodda va qattiq:
Ta'rif: Har bir tugunda balans faktori = (chap qism-daraxt balandligi) β (o'ng qism-daraxt balandligi). AVL daraxtda har tugunning balans faktori {β1, 0, +1} to'plamidan bo'lishi shart.
Agar qo'shish/o'chirishdan keyin biror tugunda balans faktori +2 yoki β2 ga chiqsa β daraxt buzilgan, va biz uni aylanish bilan darhol tuzatamiz.
Nega bu O(log n) beradi. Balansli faktor cheklangani balandlikni n ga nisbatan kichik ushlab turadi. Isbot AVL daraxtning eng "yomon" (eng kam tugunli) ko'rinishi orqali yuritiladi: balandligi h bo'lgan AVL daraxtdagi minimal tugun soni N(h) Fibonachchi rekurrentsiyasiga bo'ysunadi N(h) = N(hβ1) + N(hβ2) + 1. Bu yerdan h β€ 1.44Β·logβ(n) kelib chiqadi β ya'ni AVL daraxt balandligi to'liq muvozanatli daraxtdan ko'pi bilan 44% balandroq, demak doim O(log n).
To'rt holat: LL, RR, LR, RL¶
Balans buzilganda, qaysi tomondan og'irlik kelganiga qarab to'rt holat bo'ladi. z β balansi buzilgan eng pastki tugun bo'lsin:
| Holat | Qachon | Tuzatish |
|---|---|---|
| LL | chapning chap shoxiga qo'shildi (bf(z) > 1, chapga moyil) |
z ni o'ngga aylantirish |
| RR | o'ngning o'ng shoxiga qo'shildi (bf(z) < β1, o'ngga moyil) |
z ni chapga aylantirish |
| LR | chapning o'ng shoxiga qo'shildi | avval z.left ni chapga, so'ng z ni o'ngga |
| RL | o'ngning chap shoxiga qo'shildi | avval z.right ni o'ngga, so'ng z ni chapga |
Intuitsiya: LL va RR β "to'g'ri chiziq" buzilishi, bitta aylanish yetadi. LR va RL β "siniq chiziq" (zigzag), avval uni to'g'ri chiziqqa keltirish (1-aylanish), so'ng to'g'rilash (2-aylanish) kerak. Har holatda ko'pi bilan 2 ta aylanish, demak tuzatish O(1).
AVL ga qo'shish β qadamlar¶
insert(node, key):
1. Oddiy BST qo'shish (key < node.key -> chapga, aks holda o'ngga)
2. Yo'ldan qaytishda har tugunning balandligini yangilash
3. Shu tugunning balans faktorini hisoblash
4. Agar |bf| > 1 bo'lsa -> LL/RR/LR/RL ni aniqlab, aylanish bilan tuzatish
5. (Balanslangan) qism-daraxt ildizini yuqoriga qaytarish
Muhim nozik nuqta: qo'shish rekursiv, va biz pastdan yuqoriga qaytayotganda balandlikni yangilab, balansni tekshiramiz. AVL'da bitta qo'shishdan keyin ko'pi bilan bitta balanslash (bitta yoki ikkita aylanish) yetarli β chunki aylanish o'sha qism-daraxt balandligini qo'shishdan oldingi holatiga qaytaradi.
Python: to'liq AVL (qo'shish + aylanishlar)¶
Quyidagi kod to'liq ishlaydigan AVL daraxt. Uni ishga tushirib, ikki narsani ko'rsatamiz: (1) 1..7 ni tartib bilan qo'shganda ham balandlik faqat 3 bo'ladi (oddiy BST'da 6 bo'lardi), (2) tasodifiy n ta kalitda balandlik 1.44Β·logβ(n) chegarasidan past qoladi.
import math, random, sys
sys.setrecursionlimit(300000)
class Node:
__slots__ = ("key", "left", "right", "height")
def __init__(self, key):
self.key = key
self.left = None
self.right = None
self.height = 1 # yangi barg balandligi = 1
def h(node):
return node.height if node else 0
def balance_factor(node):
return h(node.left) - h(node.right) if node else 0
def update_height(node):
node.height = 1 + max(h(node.left), h(node.right))
def rotate_right(y):
x = y.left
t2 = x.right
x.right = y
y.left = t2
update_height(y) # avval pastdagi (y), keyin yangi ildiz (x)
update_height(x)
return x
def rotate_left(x):
y = x.right
t2 = y.left
y.left = x
x.right = t2
update_height(x)
update_height(y)
return y
def insert(node, key):
# 1) oddiy BST qo'shish
if node is None:
return Node(key)
if key < node.key:
node.left = insert(node.left, key)
elif key > node.key:
node.right = insert(node.right, key)
else:
return node # dublikat: o'zgarishsiz
# 2) balandlikni yangilash
update_height(node)
# 3-4) balansni tekshirish va 4 holatni tuzatish
bf = balance_factor(node)
if bf > 1 and key < node.left.key: # LL
return rotate_right(node)
if bf < -1 and key > node.right.key: # RR
return rotate_left(node)
if bf > 1 and key > node.left.key: # LR
node.left = rotate_left(node.left)
return rotate_right(node)
if bf < -1 and key < node.right.key: # RL
node.right = rotate_right(node.right)
return rotate_left(node)
return node # balans yaxshi
# (1) 1..7 ni TARTIB bilan qo'shamiz: oddiy BST bo'lsa balandlik 6 bo'lardi
root = None
for k in [1, 2, 3, 4, 5, 6, 7]:
root = insert(root, k)
print("balandlik (1..7 tartib bilan):", h(root))
# -> balandlik (1..7 tartib bilan): 3
# (2) Empirik: balandlik <= 1.44*log2(n) kafolatini tekshiramiz
random.seed(42)
for n in [1000, 10000, 100000]:
root = None
keys = list(range(n))
random.shuffle(keys)
for k in keys:
root = insert(root, k)
print(f"n={n:>6}: AVL balandlik={h(root):>2}, "
f"log2(n)~{math.log2(n):.1f}, 1.44*log2(n)~{1.44*math.log2(n):.1f}")
# -> n= 1000: AVL balandlik=12, log2(n)~10.0, 1.44*log2(n)~14.4
# -> n= 10000: AVL balandlik=16, log2(n)~13.3, 1.44*log2(n)~19.1
# -> n=100000: AVL balandlik=20, log2(n)~16.6, 1.44*log2(n)~23.9
Natijalarni o'qing: 100000 ta kalit uchun balandlik atigi 20 β logβ(100000) β 16.6 ga juda yaqin va 1.44Β·logβ(n) β 23.9 chegarasidan past. Bu AVL kafolati amalda ishlashining empirik tasdig'i: balandlik n bilan emas, log n bilan o'sadi.
Isbot (eskiz) β nega qo'shish
O(log n): BST qo'shishning o'zi ildizdan bargacha bitta yo'l =O(h) = O(log n). Qaytish yo'lida har tugundaO(1)ish (balandlik + balans tekshiruvi), ko'pi bilan bittaO(1)aylanish. Demak jamiO(log n) + O(log n)Β·O(1) = O(log n). β
Trassirovka: 10, 20, 30 ni qo'shish (RR holati)¶
Tartib bilan kelgan uchta kalit β eng yomon holat. AVL uni qanday tuzatishini kuzataylik:
| Qadam | Amal | Daraxt holati | Buzilgan tugun (bf) | Tuzatish |
|---|---|---|---|---|
| 1 | insert 10 | 10 |
yo'q (bf 0) | β |
| 2 | insert 20 | 10 -> o'ngda 20 |
yo'q (10 da bf β1) | β |
| 3 | insert 30 | 10 -> 20 -> 30 (tayoq) |
10 da bf = β2 | RR: 10 ni chapga aylantirish |
| natija | β | 20 ildiz, 10 chap, 30 o'ng |
hammasi bf 0 | balanslandi |
Uchinchi qo'shishdan so'ng 10 tugunda balans β2 ga chiqadi (o'ng zanjir og'ir). Bu RR holati (o'ngning o'ngiga qo'shildi), bitta chapga aylanish 10 ni pastga tushirib, 20 ni ildiz qiladi β daraxt balandligi 2 dan 1 ga tushadi.
Trade-off (AVL): Qat'iy balans tufayli AVL daraxt juda past bo'ladi, demak qidiruv eng tez β yo'l qisqa. Evaziga, qattiq shartni saqlash uchun qo'shish/o'chirishda ko'proq aylanish kerak bo'lishi mumkin. Demak AVL β ko'p qidiriladigan, kam o'zgaradigan ma'lumotlar uchun ideal.
Red-Black daraxt β bo'shroq, lekin amaliyroq balans¶
Red-Black (qizil-qora) daraxt β bugungi kunda eng ko'p ishlatiladigan balanslangan BST. U AVL kabi mukammal balansni emas, balki yetarli balansni saqlaydi: har tuguni "qizil" yoki "qora" rangga bo'yaladi, va beshta qoida bu ranglarni shunday cheklaydiki, eng uzun yo'l eng qisqasidan ko'pi bilan 2 barobar uzun bo'ladi β bu yetarli, chunki 2Β·log n = O(log n).
Beshta qoida (qisqacha):
- Har tugun yo qizil, yo qora.
- Ildiz har doim qora.
- Barcha barg (bo'sh/null) tugunlar qora deb hisoblanadi.
- Qizil tugunning ikkala farzandi ham qora (ya'ni ketma-ket ikkita qizil bo'lmaydi).
- Har bir tugundan uning ostidagi har bir bargacha bo'lgan yo'llarda bir xil sondagi qora tugun bor (bu son β "qora balandlik").
4- va 5-qoidalardan kelib chiqadigan sehr: 5-qoida har yo'lda qora tugunlar sonini tenglashtiradi; 4-qoida esa qizil tugunlar ketma-ket kelishiga yo'l qo'ymaydi. Demak eng uzun yo'l (qizil-qora-qizil-qora...) eng qisqasidan (faqat qora) ko'pi bilan ikki barobar uzun bo'ladi. Bu balandlikni β€ 2Β·logβ(n+1) da, ya'ni O(log n) da ushlab turadi.
Eslatma: Red-Black balanslashni rang almashtirish (recoloring) va aylanish kombinatsiyasi bilan amalga oshiradi. Ko'p hollarda faqat rang o'zgartiriladi (aylanishsiz), shuning uchun o'rtacha qayta balanslash kamroq bo'ladi.
AVL vs Red-Black β qaysi biri qachon¶
Ikkalasi ham barcha amalni O(log n) da kafolatlaydi, farq konstantalarda va trade-offda:
| Xususiyat | AVL | Red-Black |
|---|---|---|
| Balans qat'iyligi | qattiq (bf β {β1,0,1}) | bo'sh (β€ 2Γ yo'l) |
| Balandlik | β€ 1.44Β·logβ n (pastroq) |
β€ 2Β·logβ n (balandroq) |
| Qidiruv | tezroq (yo'l qisqa) | bir oz sekinroq |
| Qo'shish/o'chirish | sekinroq (ko'p aylanish) | tezroq (kam qayta balanslash) |
| Tipik qo'llanish | ko'p o'qiladigan indekslar | umumiy maqsadli map/set |
Aynan shu sababdan ko'p tilning standart kutubxonasi o'zgaruvchan map/set uchun Red-Black daraxtni tanlaydi: C++ std::map / std::set, Java TreeMap / TreeSet, Linux yadrosidagi ko'p planlovchilar. Qo'shish-o'chirish tez-tez bo'lganda, kamroq qayta balanslash amalda yutuq beradi. AVL esa qidiruv ustun bo'lgan vaziyatlarda (masalan, deyarli faqat o'qiladigan indeks) tanlanadi.
B-tree va B+ tree β disk uchun ko'p tarmoqli daraxt¶
AVL va Red-Black β binar daraxtlar (har tugun ko'pi bilan 2 bola), va ular xotirada (RAM) ishlashga mo'ljallangan. Lekin ma'lumotlar bazasi diskda yashaydi, va u yerda o'yin qoidalari boshqacha:
Intuitsiya: Diskdan o'qish RAM'dan o'qishdan ~100 000 marta sekin. Disk blok-blok o'qiydi (masalan, bir martada 4 KB). Demak narx β necha marta disk bloki o'qildi, ya'ni daraxt balandligi. Maqsad β balandlikni iloji boricha kichraytirish.
Binar daraxtda balandlik logβ(n). Agar tugunda 2 emas, yuzlab bola bo'lsa, balandlik log_t(n) (t β tarmoqlanish koeffitsienti) ga tushadi β bu juda kichik son. Mana B-tree g'oyasi: har tugun ko'p kalit va ko'p bolani saqlaydi, va bitta tugun aynan bitta disk blokiga mos qilib o'lchanadi.
B-tree xossalari (t β minimal daraja):
- Har tugunda
tβ1dan2tβ1gacha kalit (ildizdan tashqari), vatdan2tgacha bola. - Tugundagi kalitlar saralangan, ular bolalar oralig'idagi qiymatlarni ajratadi (xuddi BST kabi, lekin ko'p "darvoza" bilan).
- Barcha barglar bir xil chuqurlikda β bu mukammal balandlik balansini ta'minlaydi.
- Balandlik
O(log_t n).t = 100da10βΆyozuvni saqlash uchun atigi ~3 daraja kerak β ya'ni har qidiruv ~3 disk o'qish.
B+ tree β B-tree'ning amaliy varianti, real ma'lumotlar bazalari aynan shuni ishlatadi. Farqi: barcha haqiqiy ma'lumot faqat barglarda saqlanadi, ichki tugunlar esa faqat "yo'l ko'rsatkich" (kalit + ko'rsatkich). Bundan tashqari barglar bir-biriga bog'langan ro'yxat kabi ulanadi, shuning uchun diapazon so'rovlari (WHERE x BETWEEN 10 AND 50) juda tez β bir bargni topib, ro'yxat bo'ylab yurish kifoya.
Aynan shu sababdan ma'lumotlar bazasi indekslari (PostgreSQL, MySQL, SQLite default indeks) β deyarli har doim B+ tree. Ular xuddi hash-jadval kabi tez nuqta-qidiruv beradi, lekin hash-jadvaldan farqli o'laroq tartiblangan, shuning uchun diapazon va saralangan natijalar ham qo'llab-quvvatlanadi.
Halollik: B-tree va B+ tree'ning to'liq qo'shish/o'chirish kodi (tugun "bo'linishi" β split, va "birlashishi" β merge bilan) ancha katta va bu nazariy bobning doirasidan tashqarida. Bu yerda maqsad β nega disk uchun ko'p tarmoqli daraxt zarurligini va kafolatni tushunish. Amaliy nuqtai nazarni ma'lumotlar bazasi indekslari mavzusida chuqurroq ko'rish mumkin.
Murakkablik solishtirish jadvali¶
Barcha balanslangan strukturalar asosiy amallarni O(log n) da kafolatlaydi β bu oddiy BST'dan asosiy farq (BST'da O(log n) faqat o'rtacha, eng yomon holatda O(n)).
| Struktura | Qidiruv | Qo'shish | O'chirish | Eng yomon balandlik | Izoh |
|---|---|---|---|---|---|
| BST (o'rtacha) | O(log n) |
O(log n) |
O(log n) |
β | tasodifiy kirishda |
| BST (eng yomon) | O(n) |
O(n) |
O(n) |
n β 1 |
tartiblangan kirishda "tayoq" |
| AVL | O(log n) |
O(log n) |
O(log n) |
β€ 1.44Β·logβ n |
eng past, qidiruvda tez |
| Red-Black | O(log n) |
O(log n) |
O(log n) |
β€ 2Β·logβ n |
kam qayta balanslash |
| B-tree / B+ tree | O(log n) |
O(log n) |
O(log n) |
O(log_t n) |
disk uchun, juda past |
Asimptotik jihatdan (8-bob) AVL, Red-Black va B-tree bir xil β hammasi O(log n). Farq doimiy koeffitsientlarda va qaysi sharoitga moslanganida: AVL qidiruvga, Red-Black o'zgarishga, B-tree esa diskka.
Asosiy g'oyalar (bobni qisqacha)¶
- Oddiy BST eng yomon holatda
O(n)ga aylanadi (tartiblangan kirish -> "tayoq"). Yechim β daraxtni avtomatik balanslangan tutish. - Balandlik
O(log n)bo'lsa, barcha amalO(log n)kafolatlanadi. Balanslashning maqsadi aynan shu. - Aylanish (rotation) β balanslashning asosiy vositasi:
O(1), daraxt shaklini o'zgartiradi, lekin in-order tartibni (BST xossasini) saqlaydi. - AVL: qat'iy balans (har tugunda bf β {β1,0,1}). To'rt holat β LL, RR, LR, RL β bir yoki ikki aylanish bilan tuzatiladi. Balandlik
β€ 1.44Β·logβ n. Qidiruv tez, o'zgarish nisbatan sekin. - Red-Black: bo'shroq balans (5 rang qoidasi -> eng uzun yo'l β€ 2Γ eng qisqa). Kamroq qayta balanslash -> ko'p tilning standart map/set'i (Java
TreeMap, C++std::map). - B-tree / B+ tree: ko'p tarmoqli, har tugun = bir disk bloki. Balandlik juda past -> kam disk o'qish. Ma'lumotlar bazasi indekslari aynan B+ tree.
- Hammasi
O(log n)kafolat; farq β doimiy koeffitsient va qaysi sharoitga moslanganida (qidiruv / o'zgarish / disk).
Mashqlar¶
Oson¶
1-mashq. Quyidagi tugun uchun balans faktorini hisoblang: chap qism-daraxt balandligi 3, o'ng qism-daraxt balandligi 1. Bu tugun AVL shartini qoniqtiradimi?
2-mashq. Quyidagi daraxt AVL ma'nosida balanslanganmi? Har tugunning balans faktorini yozing.
3-mashq. "Eng uzun yo'l β€ 2Γ eng qisqa yo'l" β bu qaysi balanslangan strukturaning kafolati? Va nima uchun bu O(log n) balandlik beradi?
O'rta¶
4-mashq. Quyidagi daraxtni 10 (ildiz) atrofida chapga aylantiring va natijani chizing. Aylanishdan oldin va keyin in-order o'qishni yozib, ular bir xil ekanini ko'rsating.
5-mashq. Bo'sh AVL daraxtga quyidagi tartibda qo'shilganda, har qadamda balans buzilsa β qaysi holat (LL/RR/LR/RL) yuzaga keladi va qaysi aylanish bilan tuzatiladi? Kalitlar: 30, 20, 10.
6-mashq. AVL va Red-Black daraxt orasidan tanlash kerak: (a) deyarli faqat qidiriladigan lug'at (kamdan-kam o'zgaradi); (b) tez-tez qo'shilib-o'chiriladigan to'plam. Har biriga qaysi struktura mosroq va nega?
Qiyin¶
7-mashq. Bo'sh AVL daraxtga 10, 20, 30, 40, 50 ni shu tartibda qo'shing. Har qo'shishdan keyin daraxt holatini va sodir bo'lgan aylanishlarni kuzating. Yakuniy daraxt balandligi necha? (Maslahat: yuqoridagi Python kodini ishlatib tekshirsangiz bo'ladi.)
8-mashq. Nima uchun ma'lumotlar bazasi indeksi binar AVL daraxt o'rniga B+ tree ishlatadi? n = 10βΆ yozuv uchun AVL'da va B-tree'da (t = 100) qancha disk o'qish kerakligini taxminan hisoblab, javobni dalil bilan asoslang.
9-mashq. LR holati nima uchun bitta aylanish bilan tuzatilmaydi? "Chapning o'ng shoxiga qo'shildi" holatida bitta o'ngga aylanish nimaga yetarli emasligini misol bilan tushuntiring.
Yechimlar
1-mashq yechimi¶
Balans faktori = (chap balandlik) β (o'ng balandlik) = 3 β 1 = 2. AVL sharti balans faktori {β1, 0, +1} to'plamida bo'lishini talab qiladi. 2 bu to'plamda yo'q, demak bu tugun AVL shartini buzadi β balanslash (aylanish) kerak. Chap og'ir bo'lgani uchun bu LL yoki LR holati bo'ladi (chap-farzandning qaysi shoxida og'irlik borligiga qarab).
2-mashq yechimi¶
Balandliklarni pastdan hisoblaymiz (barg balandligi = 1, bo'sh = 0):
- 10: barg, balandlik 1, bf = 0
- 20: chapda 10 (balandlik 1), o'ngda bo'sh (0), balandlik 2, bf = 1 β 0 = 1
- 30: chapda 20 (balandlik 2), o'ngda bo'sh (0), balandlik 3, bf = 2 β 0 = 2 β buzildi!
- 70: barg, balandlik 1, bf = 0
- 50 (ildiz): chapda 30 (balandlik 3), o'ngda 70 (balandlik 1), bf = 3 β 1 = 2 β buzildi!
Daraxt balanslanmagan: 30 da bf = 2 va 50 da bf = 2 (ikkalasi ham {β1,0,1} dan tashqari). Chap-chap zanjir (30 -> 20 -> 10) β bu LL ko'rinishidagi buzilish.
3-mashq yechimi¶
Bu β Red-Black daraxt kafolati (5 rang qoidasidan kelib chiqadi). Nega O(log n): 5-qoida har yo'lda qora tugunlar sonini tenglashtiradi (qora balandlik b bir xil), 4-qoida esa qizil tugunlar ketma-ket kelishini taqiqlaydi. Demak eng qisqa yo'l (faqat qora) uzunligi b, eng uzun yo'l (qizil-qora navbatma-navbat) ko'pi bilan 2b. Tugunlar soni n β₯ 2^b β 1, undan b = O(log n), demak butun balandlik β€ 2b = O(log n).
4-mashq yechimi¶
Chapga aylanish (10 atrofida): 30 ko'tariladi, 10 uning chap farzandi bo'ladi, 30 ning chap farzandi B esa 10 ning o'ng farzandiga ko'chadi.
- In-order oldin:
A, 10, B, 30, C - In-order keyin:
A, 10, B, 30, C
Bir xil β BST tartib saqlandi (chunki A < 10 < B < 30 < C ikkala shaklda ham o'rinli). Bu yuqoridagi Python kodi bilan ham tasdiqlangan: rotate_left aynan shu in-order'ni qaytaradi.
5-mashq yechimi¶
| Qadam | Qo'shildi | Holat | Buzilgan tugun | Holat turi | Aylanish |
|---|---|---|---|---|---|
| 1 | 30 | 30 |
β | β | β |
| 2 | 20 | 30 -> chap 20 |
yo'q (bf 1) | β | β |
| 3 | 10 | 30 -> 20 -> 10 (chapga zanjir) |
30 da bf = +2 |
LL | 30 ni o'ngga aylantirish |
Yakuniy daraxt: 20 ildiz, 10 chap, 30 o'ng β hammasi balanslangan. Bu LL holati (chapning chap shoxiga qo'shildi), bitta o'ngga aylanish bilan tuzatildi.
6-mashq yechimi¶
(a) Deyarli faqat qidiriladigan lug'at -> AVL. AVL daraxt qat'iy balans tufayli pastroq (β€ 1.44Β·logβ n vs Red-Black β€ 2Β·logβ n), demak qidiruv yo'li qisqaroq va tezroq. O'zgarish kam bo'lgani uchun AVL'ning "ko'proq aylanish" kamchiligi deyarli sezilmaydi.
(b) Tez-tez qo'shilib-o'chiriladigan to'plam -> Red-Black. Red-Black kamroq qayta balanslash qiladi (ko'pincha faqat rang almashtirish, aylanishsiz), shuning uchun yuqori o'zgaruvchanlikda amalda tezroq. Aynan shu sababdan umumiy maqsadli standart kutubxonalar (Java TreeMap, C++ std::map) Red-Black tanlaydi.
7-mashq yechimi¶
10, 20, 30, 40, 50 ni ketma-ket qo'shamiz:
| Qadam | Qo'shildi | Buzilish | Aylanish | Natija (ildiz / shakl) |
|---|---|---|---|---|
| 1 | 10 | β | β | 10 |
| 2 | 20 | β | β | 10, o'ngda 20 |
| 3 | 30 | 10 da bf β2 |
RR: 10 chapga | ildiz 20; 10 chap, 30 o'ng |
| 4 | 40 | β | β | 20; chap 10; o'ng 30, 30 ning o'ngida 40 |
| 5 | 50 | 30 da bf β2 |
RR: 30 chapga | ildiz 20; chap 10; o'ng 40, 40 ning chap 30, o'ng 50 |
Yakuniy daraxt:
Balandlik = 2 (ildiz20 dan eng pastki bargacha 2 qirra). Oddiy BST bo'lsa balandlik 4 bo'lardi. Yuqoridagi Python kodida [10,20,30,40,50] qo'shilsa, h(root) aynan 3 qaytaradi (kod balandlikni "barg = 1" konventsiyasida sanaydi, ya'ni daraja soni = 3, qirra soni = 2 β ikkalasi bir xil daraxtni tasvirlaydi).
8-mashq yechimi¶
Asosiy sabab β disk o'qish soni = daraxt balandligi, va diskdan o'qish RAM'dan ~100 000 marta sekin, shuning uchun balandlikni minimallashtirish hal qiluvchi.
- AVL (binar): balandlik
β logβ(10βΆ) β 20. Har daraja yangi disk bloki bo'lishi mumkin -> ~20 disk o'qish. - B-tree (
t = 100): har tugunda ~100 kalit, balandlikβ logβββ(10βΆ) = 3. -> atigi ~3 disk o'qish.
~20 vs ~3 β taxminan 7 barobar kam disk o'qish. Bundan tashqari, B-tree tuguni aynan bir disk blokiga (4 KB) mos qilib o'lchanadi, demak bitta o'qishda yuzlab kalit RAM'ga keladi va ular orasida qidiruv bepul (RAM tez). B+ tree'da barglar bog'langani uchun diapazon so'rovlari ham tez. Binar AVL'da har tugun mayda va alohida disk joyida bo'lishi mumkin β ko'p, tarqoq disk o'qishlar. Shu sabab ma'lumotlar bazalari B+ tree ishlatadi.
9-mashq yechimi¶
LR holatida og'irlik chapning o'ng shoxida (zigzag/"siniq chiziq"). Bitta o'ngga aylanish to'g'ri ishlamaydi, chunki u zigzag'ni to'g'rilamaydi β faqat bir tomonga egilgan "to'g'ri chiziq" buzilishini (LL) tuzata oladi.
Misol: 30 ga 10 qo'shilib, keyin 20 qo'shilsa (10 chap, 20 esa 10 ning o'ngida):
10 ni chapga aylantirib zigzag'ni to'g'ri chiziqqa (LL ko'rinishiga) keltiramiz, so'ng 30 ni o'ngga aylantirib to'g'rilaymiz. Natija β 20 ildiz, 10 chap, 30 o'ng β balanslangan. Shuning uchun LR (va simmetrik RL) doim ikkita aylanish talab qiladi.
β¬ οΈ Oldingi: 17 β Binar qidiruv daraxti (BST) Β· π README Β· Keyingi: 19 β Heap va Priority Queue β‘οΈ