Uploaded by qodirova74

Heap Tree Binar Daraxtlar: Ma'lumotlar Tuzilmasi va Algoritmlar

advertisement
O ‘ZBEKISTON RESPUBLIKASI AXBOROT
TEXNOLOGIYALARI VA KOMMUNIKATSIYALARINI
RIVOJLANTIRISH VAZIRLIGI
MUHAMMAD AL–XORAZMIY NOMIDAGI
TOSHKENT AXBOROT TEXNOLOGIYALARI
UNIVERSITETI
FARG‘ONA FILIALI
“Telekommunikatsiya texnalogiyalari va kasb talimi ”
Fakulteti 732-22-guruh talabasi
Saloxiddinov Qobuljonning
‘’Ma’lumotlar tuzilmasi va algoritimlar”
“Mustaqil ish 2”
Bajardi: Saloxiddinov Q
Qabul qildi: Xontorayev.S.I.
MAVZU: Heap tree ko‘rinishidagi binar daraxtlar.
Heap ma’lumotlar to’plami
Binary heap – har bir tuguni (node) maxsus tartiblangan va complete binary tree.
Complete binary tree nima ekanligi haqida bu yerda tushuntirib o’tilgani uchun, maxsus
tartiblangan ma’nosiga to’xtalamiz.
Binary heap bo’lishi uchun tree’da ma’lumotlar shajara bo’yicha o’sish tartibida (max
heap) yoki kamayish tartibida (min heap) joylashgan bo’lishi kerak.
1.
Max-Heap bo’lishi uchun har bir node’ning qiymati uning parent node’ining
qiymatidan kichik yoki teng bo’lishi kerak. Eng katta qiymat root’da bo’ladi. Qoida
tree’dagi barcha node’lar uchun amal qiladi.
2.
Min-Heap bo’lishi uchun har bir node’ning qiymati uning parent node’ining
qiymatidan katta yoki teng bo’lishi kerak. Eng kichkina qiymat root’da bo’ladi. Qoida
tree’dagi barcha node’lar uchun amal qiladi.
Max
Heap va Min Heap. Image credit: https://link.medium.com/pn5E85sTeab
Binary heap nima uchun kerak?
Qisqa javob – heap’dagi eng katta (yoki eng kichik) elementni topish uchun kerak.
Bunda binary heap tuzilishi tree bo’lgani uchun eng pastki elementdan eng yuqori
elementga chiqish uchun O (log N) urinish lozim. Masalan yuqoridagi rasmda har bir
tree’da 7 ta node bo’lsa, pastdan yuqoriga chiqish – log27 = 2.8 ~ 2 ta urinishda
bo’ladi.
Priority queue maqolasida biz ro’yhatdan eng katta va eng kichik elementni topishni
ko’rgan edik. Uning kamchiligi – tartiblanmagan array uchun eng katta (yoki eng
kichik) elementni topishda time complexity O(N) bo’lib ketayotgan edi. Tartiblangan
array uchun esa, eng katta (eng kichik) elementni topish O(1) bo’ladi, lekin bunda
array element qo’shganimizda har safar array’ni tartiblashga majbur bo’linardi – O(N
log N).
Demak, Binary heap Priority queue’dan ko’ra samaraliroq ishlaydi. Qo’shish va o’chirish
– binary tree’dagi kabi O (log N).
Binary heap’ning kamchiligi – u faqat eng katta (eng kichkina) elementlarni tezda
topish imkonini beradi. Boshqa qiymatdagi elementlarni topish uchun heapni «titkilab»
chiqish kerak. Sababi binary heap – tartiblanmagan. Tabiiyki tartiblanmagan
ro’yhatdan qidirish O(N) vaqtni oladi. Masalan yuqoridagi rasm’dan 30 sonini topish
uchun heap’ning hamma elementlari tekshirib chiqish kerak bo’ladi.
Kodda ifodalash
Binary heap uchun double pointer’li linked list ishlatish shartmas. Shunchaki array
bilan ham ifodalasa bo’ladi.
Amallar osonroq bo’lishi uchun array[0] ni bo’sh qoldiramiz, keyin heap qiymatlarini
kiritamiz. Bizda Max heap’ni kodda ifodalash
const array = [null, 100, 70, 80, 20, 30, 20, 50]
Min heap:
const array = [null, 10, 14, 17, 20, 30, 21, 44]
Agar biz array’dan i-nchi elementni ko’rsak:

uning parent’i – floor (i-1)/2 indeksda;

uning chap child’i – 2 * i indeksda;

uning o’ng child’i – 2 *i + 1 indeksda.
Binary heap ustida amallar
Priority queue’da bo’lgani singari, Binary heap ustida ham ikkita amal bor. Qo’shish
(insert yoki enqueue) va eng katta (eng kichik) qiymatini o’chirish (delete yoki dequeue).
Shuningdek qo’shilgan va o’chirilgan elementlardan so’ng, heap’ning tartibini to’g’rilash
uchun ichki – cho’ktirish (sink) va ko’tarish (swim) amallari ham mavjud.
Insert. Heap’ga node (element) qo’shish uchun:
1.
Elementni tree’ning eng pastiga qo’shamiz (array’ning ohiriga qo’shamiz).
2.
Qo’shilgan elementning parent’iga qaraymiz. Agar parent’i o’zidan katta bo’lsa,
ularning o’rnini almashtiramiz.
3.
Solishtirish va almashtirishlarni element parent’idan katta bo’lguncha davom
ettiramiz.
Max heap uchun
insert amali. Image credit: https://dsucbasic.blogspot.com/2016/?m=0
Delete. O’chirish’da biz eng katta (yoki eng kichik) qiymati root’da joylashganini
bilganimiz uchun ishimiz osonroq, o’chiriladigan elementni topish O(1) vaqt oladi.
O’chirish uchun:
root elementni ohirgi element bilan o’rnini almashtiramiz: array[1] ni
1.
array[array.length – 1] bilan. Keyin ohirgi elementni o’chiramiz.
yangi root’ni uning child’lari bilan solishtiramiz. Agar u child’dan kichik bo’lsa
2.
(min heap uchun – child’dan katta bo’lsa), ularning o’rnini almashtiramiz. Ikki
child’dan ham kichkina bo’lib qolganda kattaroq qiymatdagi child bilan o’rnini
almashtiramiz.
shu tariqa solishtirish va almashtirish bilan elementni uning child’larida katta
3.
holda qolgunga qadar davom ettiramiz.
Max heap uchun
delete amali. Image credit: https://dsucbasic.blogspot.com/2016/?m=0
Qo’shish va o’chirish amallarini qanday ishlashini bilib olgach, istalgan tartiblanmagan
array’dan binary heap hosil qilishimiz mumkin.
Kod
Priority queue kabi, Binary heap’da amallar bittadan ko’p bo’lgani uchun API yozamiz.
class BinaryHeap {
constructor(arr = [], asc = true) {
this.arr = arr
this.asc = asc
}
enqueue(item) {
// Heap'ga yangi item qo'shamiz
this.arr[this.arr.length === 0 ? 1 : this.arr.length] = item
// Uning pozitsiyasini to'g'rilaymiz
this.swim(this.arr.length - 1)
}
dequeue() {
let max = this.arr[1]
// root va ohirgi element o'rnini almashtiramiz.
this.arr[1] = this.arr[this.arr.length - 1]
this.arr[this.arr.length - 1] = max
// Ohirgi elementni o'chiramiz
this.arr.pop()
// Birinchi elementning pozitsiyasini to'g'rilaymiz.
this.sink(1)
// O'chirilgan elementning qiymatini qaytaramiz
return max
}
swim(index) {
while (index > 1 &&
(
this.asc && this.arr[Math.floor(index / 2)] > this.arr[index] ||
!this.asc && this.arr[Math.floor(index / 2)] < this.arr[index]
)
) {
// Parent va child o'rnini almashtiramiz
this.swap(index, Math.floor(index / 2))
index = Math.floor(index / 2)
}
}
sink(index, len = this.arr.length) {
while (Math.floor(index / 2) <= len) {
let j = 2 * index
if (j < len &&
(
this.asc && this.arr[j] > this.arr[j + 1] ||
!this.asc && this.arr[j] < this.arr[j + 1]
)
) {
j++
}
if (!(this.asc && this.arr[index] > this.arr[j] || !this.asc && this.arr[index] <
this.arr[j])) {
break
}
this.swap(index, j)
index = j
}
}
isEmpty() {
// heap bo'shligini tekshirish
return this.arr.length < 2
}
swap(a, b) {
[this.arr[a], this.arr[b]] = [this.arr[b], this.arr[a]]
}
show() {
return this.arr
}
}
/**
* USAGE
*/
const array = [3, 4, 6, 2, 9, 1]
const binaryHeap = new BinaryHeap([], false)
array.map(item => binaryHeap.enqueue(item))
binaryHeap.dequeue()
console.log(binaryHeap.show())
Download