DSA Interview Prep · पाठ

Heapify, Push और Pop शुरुआत से

push के लिए heapify-up और pop के लिए heapify-down लागू कीजिए, फिर Floyd के एल्गोरिदम से अव्यवस्थित ऐरे से O(n) में heap बनाइए।

पाठ 2, कुल 4 में से13 चरण

Heapify, Push और Pop शुरुआत से, CoddyKit पर DSA Interview Prep का एक निःशुल्क पाठ है। यह 4 में से 2वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह DSA Interview Prep सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। DSA Interview Prep पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

MinHeap क्लास बनाना

हीप को शून्य से लागू करना इसकी आंतरिक कार्यप्रणाली पर आपकी पकड़ दिखाता है और कभी-कभी वरिष्ठ स्तर के इंटरव्यू में पूछा जाता है। एक MinHeap क्लास सारणी को समेटती है और push, pop, peek तथा size क्रियाएँ उपलब्ध कराती है। आंतरिक रूप से, यह push के बाद sift-up और pop के बाद sift-down बुलाकर हीप गुण बनाए रखती है। इस कार्यान्वयन को समझने पर Python का heapq मॉड्यूल पूरी तरह स्पष्ट हो जाता है।

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

    def push(self, val):
        self._data.append(val)
        self._sift_up(len(self._data) - 1)

    def pop(self):
        if len(self._data) == 1:
            return self._data.pop()
        min_val = self._data[0]
        self._data[0] = self._data.pop()  # move last to root
        self._sift_down(0)
        return min_val

    def peek(self):
        return self._data[0] if self._data else None

    def size(self):
        return len(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

print('MinHeap class skeleton defined')

Sift-Up लागू करना

Sift-up किसी नोड की उसके parent से तुलना करता है और जब तक हीप गुण (min-heap के लिए parent <= child) का उल्लंघन होता है, तब तक उसे ऊपर की ओर अदला-बदली करता है। मुख्य बात यह है कि नया डाला गया तत्व अंत में होता है और अपने सही स्थान तक ऊपर उठता है। while लूप अधिकतम floor(log n) बार चलता है — यह ट्री की ऊँचाई है। ऊपर की ओर बढ़ते रहने के लिए प्रत्येक चरण में i = parent निर्धारित करें।

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 _sift_up(self, i):
        while i > 0:
            p = self._parent(i)
            if self._data[p] > self._data[i]:  # parent > child: swap
                self._data[p], self._data[i] = self._data[i], self._data[p]
                i = p
            else:
                break  # heap property satisfied

    def push(self, val):
        self._data.append(val)
        self._sift_up(len(self._data) - 1)

h = MinHeap()
for v in [5, 3, 8, 1, 4]:
    h.push(v)
print(h._data)  # valid min-heap

Sift-Down लागू करना

Sift-down किसी नोड को उसके सबसे छोटे child के साथ बार-बार अदला-बदली करके नीचे ले जाता है (min-heap के लिए), जब तक कोई भी child उससे छोटा न हो या नोड पत्ती तक न पहुँच जाए। हमेशा दोनों children से तुलना करें और हीप गुण बनाए रखने के लिए छोटे child के साथ अदला-बदली करें। मानों की तुलना करने से पहले यह जाँचना याद रखें कि child के सूचकांक मान्य सीमा में हैं।

def _sift_down(data, i):
    n = len(data)
    while True:
        smallest = i
        l = 2 * i + 1
        r = 2 * i + 2
        if l < n and data[l] < data[smallest]:
            smallest = l
        if r < n and data[r] < data[smallest]:
            smallest = r
        if smallest == i:
            break  # already the smallest among i, l, r
        data[i], data[smallest] = data[smallest], data[i]
        i = smallest

# Test: put a large value at root and sift down
heap = [10, 1, 2, 3, 4, 5, 6]
print('Before sift-down:', heap)
_sift_down(heap, 0)
print('After sift-down:', heap)  # 1 should reach top, 10 sink

Pop के साथ पूर्ण MinHeap

Pop क्रिया मूल को हटाकर लौटाती है (min-heap में यह न्यूनतम मान होता है)। पूर्ण बाइनरी ट्री का आकार बनाए रखने के लिए अंतिम तत्व को मूल के स्थान पर ले जाएँ, फिर उसे sift-down करें। इससे सारणी में रिक्त स्थान नहीं बनते और निरूपण मान्य बना रहता है। विशेष स्थिति: यदि केवल एक तत्व बचा हो, तो उसे sift-down किए बिना सीधे निकालकर लौटा दें।

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

    def push(self, val):
        self._data.append(val)
        i = len(self._data) - 1
        while i > 0:
            p = (i - 1) // 2
            if self._data[p] > self._data[i]:
                self._data[p], self._data[i] = self._data[i], self._data[p]
                i = p
            else: break

    def pop(self):
        if not self._data: return None
        if len(self._data) == 1: return self._data.pop()
        result = self._data[0]
        self._data[0] = self._data.pop()  # last -> root
        i, n = 0, len(self._data)
        while True:
            s, l, r = i, 2*i+1, 2*i+2
            if l < n and self._data[l] < self._data[s]: s = l
            if r < n and self._data[r] < self._data[s]: s = r
            if s == i: break
            self._data[i], self._data[s] = self._data[s], self._data[i]
            i = s
        return result

h = MinHeap()
for v in [5, 3, 8, 1, 4, 2]: h.push(v)
print([h.pop() for _ in range(6)])  # [1,2,3,4,5,8] sorted

Floyd का Heapify एल्गोरिदम

Floyd का एल्गोरिदम प्रत्येक गैर-पत्ती नोड पर sift-down बुलाकर O(n) में अक्रमबद्ध सारणी से min-heap बनाता है। यह अंतिम आंतरिक नोड (n//2 - 1) से शुरू होकर मूल की ओर बढ़ता है। पत्तियाँ पहले से ही एक-तत्व वाले वैध हीप होती हैं। O(n) समय-सीमा इस तथ्य से आती है कि अधिकांश नोड ट्री के निचले भाग के पास होते हैं और उन्हें केवल थोड़ी दूरी तक sift-down करना पड़ता है।

def heapify(arr):
    n = len(arr)
    # Start from last non-leaf: index n//2 - 1
    # Work backward to root (index 0)
    for i in range(n // 2 - 1, -1, -1):
        # Sift down node at index i
        j = i
        while True:
            s = j
            l, r = 2*j+1, 2*j+2
            if l < n and arr[l] < arr[s]: s = l
            if r < n and arr[r] < arr[s]: s = r
            if s == j: break
            arr[j], arr[s] = arr[s], arr[j]
            j = s
    return arr

arr = [9, 7, 5, 3, 1, 8, 2, 4, 6]
print('Before:', arr)
heapify(arr)
print('After (min-heap):', arr)  # arr[0] should be 1

Floyd का एल्गोरिदम O(n) क्यों है

O(n) का प्रमाण: ऊँचाई k पर ट्री में n/2^(k+1) नोड होते हैं। ऊँचाई k का प्रत्येक नोड sift-down के दौरान अधिकतम k अदला-बदलियाँ करता है। कुल कार्य = सभी ऊँचाइयों k पर योग: n/2^(k+1) * k। यह ज्यामितीय श्रेणी O(n) तक अभिसरित होती है। इसकी तुलना सरल एक-एक करके प्रविष्टि से करें: प्रत्येक push O(log n) होता है, इसलिए n push की लागत O(n log n) होती है। बैच निर्माण के लिए Floyd का एल्गोरिदम स्पष्ट रूप से बेहतर है।

import time
import random

# Compare: O(n) heapify vs O(n log n) one-by-one
n = 100000
data = list(range(n, 0, -1))  # reverse sorted = worst case for push

# Method 1: Floyd's O(n)
data1 = data[:]
start = time.time()
for i in range(n // 2 - 1, -1, -1):
    j = i
    while True:
        s = j; l, r = 2*j+1, 2*j+2
        if l < n and data1[l] < data1[s]: s = l
        if r < n and data1[r] < data1[s]: s = r
        if s == j: break
        data1[j], data1[s] = data1[s], data1[j]; j = s
print(f'Floyd heapify: {time.time()-start:.4f}s')

# Method 2: One-by-one insertion
import heapq
start = time.time()
heap = []
for x in data: heapq.heappush(heap, x)
print(f'Push one-by-one: {time.time()-start:.4f}s')

मौजूदा संग्रह में Heap Push

Python के heapq.heappushpop और heapq.heapreplace कुशल संयुक्त क्रियाएँ हैं। heappushpop(heap, item) नए item को push करता है और तुरंत सबसे छोटा मान pop करता है — यह दो अलग-अलग कॉल की तुलना में अधिक कुशल है। heapreplace(heap, item) एक ही चरण में सबसे छोटा मान pop करता है और नया item push करता है (सही परिणाम के लिए नया item पुराने न्यूनतम मान से >= होना चाहिए)। ये शीर्ष-k प्रवाह एल्गोरिदम में उपयोगी हैं।

import heapq

heap = [1, 3, 5, 7, 9]
heapq.heapify(heap)

# heappushpop: push 2, then pop minimum
# More efficient than push + pop separately
result = heapq.heappushpop(heap, 2)
print('heappushpop(2):', result, '| heap:', heap)

# heapreplace: pop minimum, then push new item
# New item does NOT need to be larger (different from heappushpop)
result2 = heapq.heapreplace(heap, 4)
print('heapreplace(4):', result2, '| heap:', heap)

# Use case: maintaining a fixed-size top-k heap
# heappushpop is the standard pattern

शून्य से MaxHeap लागू करना

एक MaxHeap तुलना की दिशा उलट देता है: parent अपने सभी descendants से बड़ा या उनके बराबर होना चाहिए। Sift-up और sift-down में तुलना को उलट दें। वैकल्पिक रूप से, मानों को ऋणात्मकता वाले किसी क्लास में लपेटें या Python के heapq की तरह पूर्णांकों का ऋणात्मक रूप लें। शून्य से इसका कार्यान्वयन दिखाता है कि min और max हीप केवल तुलना संचालक में बदलाव के साथ समान संरचनाएँ हैं।

class MaxHeap:
    def __init__(self):
        self._data = []

    def push(self, val):
        self._data.append(val)
        i = len(self._data) - 1
        while i > 0:
            p = (i - 1) // 2
            if self._data[p] < self._data[i]:  # FLIP: parent < child = violation
                self._data[p], self._data[i] = self._data[i], self._data[p]
                i = p
            else: break

    def pop(self):
        if not self._data: return None
        if len(self._data) == 1: return self._data.pop()
        result = self._data[0]
        self._data[0] = self._data.pop()
        i, n = 0, len(self._data)
        while True:
            g = i; l, r = 2*i+1, 2*i+2
            if l < n and self._data[l] > self._data[g]: g = l  # FLIP
            if r < n and self._data[r] > self._data[g]: g = r  # FLIP
            if g == i: break
            self._data[i], self._data[g] = self._data[g], self._data[i]; i = g
        return result

h = MaxHeap()
for v in [5, 3, 8, 1, 4, 2]: h.push(v)
print([h.pop() for _ in range(6)])  # [8,5,4,3,2,1]

हीप से मनमाना तत्व हटाना

हीप से किसी मनमाने तत्व (मूल को छोड़कर) को हटाने में O(log n) समय लगता है, लेकिन इसके लिए तत्व का सूचकांक ज्ञात होना चाहिए। उस तत्व को अंतिम तत्व से बदलें, अंतिम तत्व हटाएँ, फिर बदले गए तत्व पर sift-up या sift-down करें (हीप गुण का उल्लंघन केवल एक ही दिशा में होगा)। इस तकनीक का उपयोग Dijkstra के एल्गोरिदम में विलंबित विलोपन के साथ और decrease-key क्रियाओं का समर्थन करने वाली प्राथमिकता कतारों में किया जाता है।

def delete_at_index(heap, i):
    n = len(heap)
    heap[i] = heap[n - 1]
    heap.pop()
    if i >= len(heap):
        return  # deleted the last element
    # Try sift-up first
    p = (i - 1) // 2
    if i > 0 and heap[i] < heap[p]:
        while i > 0:
            p = (i - 1) // 2
            if heap[p] > heap[i]:
                heap[p], heap[i] = heap[i], heap[p]; i = p
            else: break
    else:  # sift down
        j = i; n2 = len(heap)
        while True:
            s = j; l, r = 2*j+1, 2*j+2
            if l < n2 and heap[l] < heap[s]: s = l
            if r < n2 and heap[r] < heap[s]: s = r
            if s == j: break
            heap[j], heap[s] = heap[s], heap[j]; j = s

heap = [1, 3, 2, 7, 4, 5, 6]
print('Before:', heap)
delete_at_index(heap, 2)  # delete element at index 2 (value=2)
print('After:', heap)  # 2 removed, heap still valid

शीर्ष-k सबसे अधिक बार आने वाले तत्वों में हीप

शीर्ष-K सबसे अधिक बार आने वाले तत्व (LeetCode #347) k आकार के min-heap का उपयोग करते हैं। ऐसी min-heap बनाए रखें जिसमें प्रत्येक प्रविष्टि (frequency, element) हो। प्रत्येक अद्वितीय तत्व को संसाधित करें: यदि हीप में k से कम तत्व हों, तो push करें; अन्यथा, यदि नए तत्व की frequency हीप के न्यूनतम मान से अधिक हो, तो न्यूनतम मान को pop करके नया तत्व push करें। अंतिम हीप में O(n log k) समय में सबसे अधिक बार आने वाले k तत्व होते हैं।

import heapq
from collections import Counter

def top_k_frequent(nums, k):
    count = Counter(nums)
    # Min-heap of (frequency, num)
    heap = []
    for num, freq in count.items():
        heapq.heappush(heap, (freq, num))
        if len(heap) > k:
            heapq.heappop(heap)  # remove least frequent
    return [num for freq, num in heap]

print(top_k_frequent([1,1,1,2,2,3], 2))  # [1, 2]
print(top_k_frequent([4,4,4,3,3,2,1], 2)) # [4, 3]

शेड्यूलिंग में हीप के अनुप्रयोग

प्रतिस्पर्धी प्रोग्रामिंग के अलावा, हीप वास्तविक दुनिया की शेड्यूलिंग प्रणालियों को संचालित करते हैं। ऑपरेटिंग सिस्टम के कार्य शेड्यूलर प्राथमिकता कतार (हीप) का उपयोग करते हैं, ताकि सबसे अधिक प्राथमिकता वाली तैयार प्रक्रिया हमेशा चलाई जाए। घटना-आधारित अनुकरण, घटना के समय के आधार पर कुंजीकृत min-heap का उपयोग करके घटनाओं को समय-क्रम में संसाधित करते हैं। नेटवर्क पैकेट शेड्यूलर सेवा-गुणवत्ता वर्ग के आधार पर ट्रैफ़िक को प्राथमिकता देते हैं। हीप को समझने से आपको इन सभी प्रणालियों का एक मानसिक मॉडल मिलता है और कतारबंदी तथा प्रणाली-अभिकल्पना से जुड़े साक्षात्कारों में इसका स्वाभाविक रूप से सामना होता है।

import heapq

# Simple event-driven simulation using a heap
events = []  # (time, event_description)

def schedule(time, event):
    heapq.heappush(events, (time, event))

def process_next():
    time, event = heapq.heappop(events)
    print(f't={time}: {event}')
    return time, event

# Schedule events out of order:
schedule(10, 'Send email')
schedule(3,  'Open app')
schedule(7,  'Process request')
schedule(1,  'Start server')

# Process in time order:
while events:
    process_next()
# Output: t=1, t=3, t=7, t=10 -- always in time order

त्वरित जाँच

इस पाठ में दिए गए डेटा संरचनाएँ और एल्गोरिद्म — कोडिंग इंटरव्यू की तैयारी से जुड़े विचारों की अपनी समझ जाँचें।

पाठ का पुनरावलोकन

इस पाठ में आपने सीखा: सिफ्ट-अप और सिफ्ट-डाउन के साथ शून्य से MinHeap और MaxHeap बनाना, Floyd का O(n) heapify एल्गोरिद्म और यह कि यह एक-एक करके O(n log n) प्रविष्टि से बेहतर क्यों है, तथा व्यावहारिक अनुप्रयोग जिनमें शीर्ष-k बारंबार आने वाले तत्व और अनुक्रमणिका पर विलोपन शामिल हैं। आगे हम Python के heapq मॉड्यूल और max-heap की युक्तियों का अध्ययन करेंगे।

शुरुआत निःशुल्क

एआई शिक्षक के साथ Python सीखें — निःशुल्क

अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।

पाठ्यक्रम
30
पाठ
120

अक्सर पूछे जाने वाले प्रश्न

क्या “Heapify, Push और Pop शुरुआत से” पाठ निःशुल्क है?

हाँ — DSA Interview Prep अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “Heapify, Push और Pop शुरुआत से” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। DSA Interview Prep पाठ्यक्रम में कुल 4 पाठ शामिल हैं।

“Heapify, Push और Pop शुरुआत से” में मैं क्या सीखूँगा?

push के लिए heapify-up और pop के लिए heapify-down लागू कीजिए, फिर Floyd के एल्गोरिदम से अव्यवस्थित ऐरे से O(n) में heap बनाइए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ DSA Interview Prep का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।

क्या DSA Interview Prep शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?

पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर DSA Interview Prep शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 2वाँ पाठ है।

“Heapify, Push और Pop शुरुआत से” पाठ पूरा करने में कितना समय लगता है?

CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।

क्या मैं इस DSA Interview Prep पाठ में कोड लिख और चला सकता हूँ?

हाँ। हर DSA Interview Prep पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।

इस पाठ्यक्रम के सभी पाठ

  1. Heap गुण और ऐरे निरूपण
  2. Heapify, Push और Pop शुरुआत से
  3. Python heapq और Max-Heap युक्तियाँ
  4. डेटा प्रवाह का माध्यिका और K-तरफ़ा विलय
← DSA Interview Prep पर वापस जाएँ