8-bo‘lim
Daraxtlar
Daraxt atamalari, ikkilik daraxt, uni aylanib chiqishning to'rt usuli va daraxtlar qayerda ishlatilishi.
Ushbu bo‘lim mundarijasi
Shu paytgacha ko'rgan tuzilmalarimiz chiziqli edi - elementlar bir qatorda joylashgan. Lekin ko'p ma'lumotlar tabiatan ierarxik: papkalar ichida papkalar, bo'limlar ichida bo'limlar, boshliq ostida xodimlar.
Daraxt atamalari #
| Atama | Ma'nosi |
|---|---|
| Ildiz (root) | Eng yuqoridagi tugun, otasi yo'q |
| Ota (parent) | Tepadagi bog'langan tugun |
| Bola (child) | Pastdagi bog'langan tugun |
| Barg (leaf) | Bolasi bo'lmagan tugun |
| Aka-uka (sibling) | Bitta otaga tegishli tugunlar |
| Daraja (depth) | Ildizdan tugungacha bo'lgan masofa |
| Balandlik (height) | Ildizdan eng uzoq bargacha masofa |
| Qism daraxt | Har qanday tugun va uning avlodlari |
Daraxt - sikli yo'q va bog'langan graf. n ta tugunli daraxtda har doim aynan n - 1 ta qirra bo'ladi.
Graflarni 11-bo'limda ko'ramiz.
Ikkilik daraxt (Binary Tree) #
Eng ko'p ishlatiladigan tur: har bir tugunning ko'pi bilan ikkita bolasi bo'ladi - chap va o'ng.
class DaraxtTuguni:
"""Ikkilik daraxt tuguni."""
def __init__(self, qiymat):
self.qiymat = qiymat
self.chap = None
self.ong = None
def __repr__(self):
return f"Tugun({self.qiymat})"
# A
# / \
# B C
# / \ \
# D E F
ildiz = DaraxtTuguni("A")
ildiz.chap = DaraxtTuguni("B")
ildiz.ong = DaraxtTuguni("C")
ildiz.chap.chap = DaraxtTuguni("D")
ildiz.chap.ong = DaraxtTuguni("E")
ildiz.ong.ong = DaraxtTuguni("F")
print(ildiz, ildiz.chap, ildiz.chap.chap)
Tugun(A) Tugun(B) Tugun(D)
Ikkilik daraxt turlari #
| Turi | Sharti |
|---|---|
| To'liq (full) | Har bir tugunda 0 yoki 2 ta bola |
| Mukammal (perfect) | Barcha barglar bir darajada, hamma ichki tugun to'la |
| Butun (complete) | Oxirgisidan boshqa barcha daraja to'la, oxirgisi chapdan to'ladi |
| Muvozanatli (balanced) | Chap va o'ng balandlik farqi 1 dan oshmaydi |
Daraxtdagi barcha amallar balandlikka bog'liq. Muvozanatli daraxtda balandlik log₂(n),
ya'ni million tugun uchun atigi 20 daraja. Muvozanatsiz daraxt esa bog'langan ro'yxatga
aylanib qoladi va balandlik n bo'ladi. Farq O(log n) va O(n) o'rtasida.
Daraxtni aylanib chiqish #
Chiziqli tuzilmada bitta yo'l bor - boshidan oxirigacha. Daraxtda esa to'rtta asosiy usul mavjud.
def preorder(tugun, natija=None):
"""Ota -> chap -> o'ng. Daraxt nusxasini yaratish uchun qulay."""
if natija is None:
natija = []
if tugun is not None:
natija.append(tugun.qiymat)
preorder(tugun.chap, natija)
preorder(tugun.ong, natija)
return natija
def inorder(tugun, natija=None):
"""Chap -> ota -> o'ng. Qidiruv daraxtida tartiblangan ketma-ketlik beradi."""
if natija is None:
natija = []
if tugun is not None:
inorder(tugun.chap, natija)
natija.append(tugun.qiymat)
inorder(tugun.ong, natija)
return natija
def postorder(tugun, natija=None):
"""Chap -> o'ng -> ota. Daraxtni o'chirish uchun qulay."""
if natija is None:
natija = []
if tugun is not None:
postorder(tugun.chap, natija)
postorder(tugun.ong, natija)
natija.append(tugun.qiymat)
return natija
print("Preorder: ", preorder(ildiz))
print("Inorder: ", inorder(ildiz))
print("Postorder:", postorder(ildiz))
Preorder: ['A', 'B', 'D', 'E', 'C', 'F']
Inorder: ['D', 'B', 'E', 'A', 'C', 'F']
Postorder: ['D', 'E', 'B', 'F', 'C', 'A']
Daraja bo'yicha aylanish (BFS) #
Bu yagona usul bo'lib, rekursiya emas, navbat ishlatadi:
from collections import deque
def daraja_boyicha(ildiz):
"""Daraxtni yuqoridan pastga, chapdan o'ngga aylanadi."""
if ildiz is None:
return []
natija = []
navbat = deque([ildiz])
while navbat:
tugun = navbat.popleft()
natija.append(tugun.qiymat)
if tugun.chap:
navbat.append(tugun.chap)
if tugun.ong:
navbat.append(tugun.ong)
return natija
def darajalar_boyicha(ildiz):
"""Har bir darajani alohida ro'yxat qilib qaytaradi."""
if ildiz is None:
return []
darajalar = []
navbat = deque([ildiz])
while navbat:
daraja_hajmi = len(navbat)
joriy_daraja = []
for _ in range(daraja_hajmi):
tugun = navbat.popleft()
joriy_daraja.append(tugun.qiymat)
if tugun.chap:
navbat.append(tugun.chap)
if tugun.ong:
navbat.append(tugun.ong)
darajalar.append(joriy_daraja)
return darajalar
print("Daraja bo'yicha:", daraja_boyicha(ildiz))
for raqam, daraja in enumerate(darajalar_boyicha(ildiz)):
print(f" {raqam}-daraja: {daraja}")
Daraja bo'yicha: ['A', 'B', 'C', 'D', 'E', 'F']
0-daraja: ['A']
1-daraja: ['B', 'C']
2-daraja: ['D', 'E', 'F']
| Usul | Qachon |
|---|---|
| Preorder | Daraxt nusxasini olish, ifodani prefiks yozuvga o'girish |
| Inorder | Qidiruv daraxtidan tartiblangan ro'yxat olish |
| Postorder | Daraxtni o'chirish, papka hajmini hisoblash |
| Level order | Eng qisqa yo'l, daraja bo'yicha tahlil |
Foydali daraxt funksiyalari #
def balandlik(tugun):
"""Daraxt balandligini qaytaradi. O(n)."""
if tugun is None:
return -1
return 1 + max(balandlik(tugun.chap), balandlik(tugun.ong))
def tugunlar_soni(tugun):
"""Jami tugunlar soni. O(n)."""
if tugun is None:
return 0
return 1 + tugunlar_soni(tugun.chap) + tugunlar_soni(tugun.ong)
def barglar_soni(tugun):
"""Barglar soni. O(n)."""
if tugun is None:
return 0
if tugun.chap is None and tugun.ong is None:
return 1
return barglar_soni(tugun.chap) + barglar_soni(tugun.ong)
def muvozanatli_mi(tugun):
"""Daraxt muvozanatli ekanini tekshiradi."""
def tekshir(t):
if t is None:
return 0, True
chap_balandlik, chap_ok = tekshir(t.chap)
ong_balandlik, ong_ok = tekshir(t.ong)
joriy_ok = chap_ok and ong_ok and abs(chap_balandlik - ong_balandlik) <= 1
return 1 + max(chap_balandlik, ong_balandlik), joriy_ok
return tekshir(tugun)[1]
print(f"Balandlik: {balandlik(ildiz)}")
print(f"Tugunlar soni: {tugunlar_soni(ildiz)}")
print(f"Barglar soni: {barglar_soni(ildiz)}")
print(f"Muvozanatlimi: {muvozanatli_mi(ildiz)}")
Balandlik: 2
Tugunlar soni: 6
Barglar soni: 3
Muvozanatlimi: True
Daraxtni chiroyli chiqarish #
Nosozlikni tuzatishda juda foydali:
def daraxtni_chiz(tugun, prefiks="", chapmi=True):
"""Daraxtni terminalda ko'rsatadi."""
if tugun is None:
return
daraxtni_chiz(tugun.ong, prefiks + ("| " if chapmi else " "), False)
print(prefiks + ("+-- " if chapmi else "+-- ") + str(tugun.qiymat))
daraxtni_chiz(tugun.chap, prefiks + (" " if chapmi else "| "), True)
daraxtni_chiz(ildiz)
+-- F
+-- C
| +-- E
+-- A
| +-- B
+-- D
Daraxtlar qayerda ishlatiladi? #
| Soha | Qo'llanilishi |
|---|---|
| Fayl tizimi | Papkalar ierarxiyasi |
| Veb-brauzer | HTML DOM daraxti |
| Ma'lumotlar bazasi | B-daraxt indekslari |
| Kompilyatorlar | Abstrakt sintaksis daraxti (AST) |
| Sun'iy intellekt | Qaror daraxtlari, o'yin daraxtlari |
| Siqish | Huffman kodlash daraxti |
| Tarmoq | Marshrutlash jadvallari |
Ushbu sahifaning HTML tuzilishi - daraxt. <html> ildiz, <body> uning bolasi,
har bir <div> va <p> esa pastroq tugunlar. Brauzer sahifani ko'rsatishda
aynan shu daraxtni aylanib chiqadi.
eng_katta_qiymat(tugun)funksiyasini yozing - daraxtdagi eng katta qiymatni toping.daraxtlar_bir_xilmi(a, b)- ikki daraxt bir xil ekanini tekshiring.oynadagi_aks(tugun)- daraxtning chap va o'ng tomonlarini almashtiring.- Berilgan darajadagi tugunlar sonini qaytaruvchi funksiya yozing.
preorderni rekursiyasiz, stek yordamida qayta yozing.
Xulosa #
- Daraxt - ierarxik ma'lumotlar uchun tuzilma: ildiz, ichki tugunlar va barglardan iborat.
- Ikkilik daraxtda har bir tugunning ko'pi bilan ikkita bolasi bo'ladi.
- Aylanib chiqishning to'rt usuli: preorder, inorder, postorder va daraja bo'yicha.
- Dastlabki uchtasi rekursiya (stek), oxirgisi navbat ishlatadi.
- Daraxtdagi amallar tezligi balandlikka bog'liq: muvozanatlida O(log n), muvozanatsizda O(n).
Keyingi bo'limda daraxtga tartib qo'shamiz va uni qidiruv vositasiga aylantiramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.