DSA Material

Heap va Navbat (Priority Queue)

Share to

Heap — bu massivda saqlanadigan to'liq ikkilik daraxt (complete binary tree).

Kitobga moslik

Navbat (priority queue) ADT'si Necaise kitobining 8-bobida (Queues) keltirilgan.
Ushbu sahifa bu materialni heap'ga asoslangan implementatsiya bilan kengaytiradi — bu esa amaliyotda standart yondashuv hisoblanadi.

Navbatlar (priority queue) odatda heap'lar ustiga quriladi.

Heap invariantlari

Massivga asoslangan heap'da indekslar mosligi

Operatsiyalar

push(value)

Oxiriga qo'shing, so'ng heap xususiyati buzilgan bo'lsa, yuqoriga ko'tarib (sift up) joylashtiring.

Heap push

def push(self, value):
    self.data.append(value)
    self._sift_up(len(self.data) - 1)

pop()

Ildizni (root) olib tashlang, oxirgi elementni ildizga ko'chiring, so'ng heap xususiyati tiklanguncha pastga tushiring (sift down).

Heap pop

def pop(self):
    if not self.data:
        raise IndexError('pop from empty heap')

    root = self.data[0]
    last = self.data.pop()
    if self.data:
        self.data[0] = last
        self._sift_down(0)
    return root

peek()

Ildiz (root) elementini qaytaradi. Min-heap'da bu eng kichik qiymat bo'ladi.

def peek(self):
    if not self.data:
        raise IndexError('peek from empty heap')
    return self.data[0]

To'liq implementatsiya

class MinHeap:
    def __init__(self):
        self.data = []

    def _parent(self, i):
        return (i - 1) // 2

    def _left(self, i):
        return 2 * i + 1

    def _right(self, i):
        return 2 * i + 2

    def push(self, value):
        self.data.append(value)
        self._sift_up(len(self.data) - 1)

    def pop(self):
        if not self.data:
            raise IndexError('pop from empty heap')

        root = self.data[0]
        last = self.data.pop()
        if self.data:
            self.data[0] = last
            self._sift_down(0)
        return root

    def peek(self):
        if not self.data:
            raise IndexError('peek from empty heap')
        return self.data[0]

    def _sift_up(self, i):
        while i > 0:
            parent = self._parent(i)
            if self.data[parent] <= self.data[i]:
                return
            self.data[parent], self.data[i] = self.data[i], self.data[parent]
            i = parent

    def _sift_down(self, i):
        n = len(self.data)
        while True:
            left = self._left(i)
            right = self._right(i)
            smallest = i

            if left < n and self.data[left] < self.data[smallest]:
                smallest = left
            if right < n and self.data[right] < self.data[smallest]:
                smallest = right

            if smallest == i:
                return

            self.data[i], self.data[smallest] = self.data[smallest], self.data[i]
            i = smallest

Heap'ni chiziqli vaqtda qurish

Agar sizda allaqachon massiv bo'lsa, pastdan yuqoriga (bottom-up) heapify usuli heap'ni O(n) vaqtda quradi.

def heapify(nums):
    h = MinHeap()
    h.data = nums[:]  # nusxa olish

    start = (len(h.data) // 2) - 1
    for i in range(start, -1, -1):
        h._sift_down(i)
    return h

Navbat (priority queue) namunasi

(priority, payload) ko'rinishidagi tuple'lardan foydalaning — shunda eng kichik prioritetli element birinchi bo'lib olinadi.

h = MinHeap()
h.push((2, "email"))
h.push((1, "payment"))
print(h.pop())  # (1, "payment")

Prioritetlar teng bo'lganda, agar barqaror tartib muhim bo'lsa, tenglikni hal qiluvchi (tie-breaker) hisoblagich qo'shing.

Murakkablik xulosasi

Operatsiya Vaqt
Push O(log n)
Pop O(log n)
Peek O(1)
Heap qurish O(n)

Odatiy qo'llanishlari

Odatiy xatolar