{"record":{"id":"596b6a58c2db3f4f","repo":"krahets/hello-algo","slug":"error-596b6a","errorCode":null,"errorMessage":"куча пуста","messagePattern":"куча пуста","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"ru/codes/ruby/chapter_heap/my_heap.rb","lineNumber":83,"sourceCode":"\n  ### Начиная с узла i, выполнить просеивание снизу вверх ###\n  def sift_up(i)\n    loop do\n      # Получение родительского узла для узла i\n      p = parent(i)\n      # Завершить heapify, когда «корневой узел уже пройден» или «узел не требует исправления»\n      break if p < 0 || @max_heap[i] <= @max_heap[p]\n      # Поменять два узла местами\n      swap(i, p)\n      # Циклическое просеивание вверх\n      i = p\n    end\n  end\n\n  ### Извлечение элемента из кучи ###\n  def pop\n    # Обработка пустого случая\n    raise IndexError, \"куча пуста\" if is_empty?\n    # Поменять корневой узел с самым правым листом местами (поменять первый и последний элементы)\n    swap(0, size - 1)\n    # Удаление узла\n    val = @max_heap.pop\n    # Просеивание сверху вниз\n    sift_down(0)\n    # Вернуть элемент с вершины кучи\n    val\n  end\n\n  ### Начиная с узла i, выполнить просеивание сверху вниз ###\n  def sift_down(i)\n    loop do\n      # Определить узел с максимальным значением среди i, l и r и обозначить его как ma\n      l, r, ma = left(i), right(i), i\n      ma = l if l < size && @max_heap[l] > @max_heap[ma]\n      ma = r if r < size && @max_heap[r] > @max_heap[ma]\n","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/ru/codes/ruby/chapter_heap/my_heap.rb#L65-L101","documentation":"Raised by MaxHeap#pop (ru) — extract the maximum — when `is_empty?`. The guard runs before the swap-root-with-last-leaf, pop, and sift_down sequence, because there is no root to extract. This is the standard empty-heap precondition; pop is the only mutating accessor and does not delegate to a peek, so the raise is at the pop entry.","triggerScenarios":"Calling `heap.pop` on a freshly constructed heap, or after extracting all elements. Any extract-max loop that overshoots the heap's size triggers it.","commonSituations":"Heap-sort or top-k loop that pops N+1 times; draining a priority queue then popping again; a driver that pops before the first push.","solutions":["Guard with `heap.is_empty?` (or `heap.size > 0`) before pop.","Drive extract loops with `until heap.is_empty?`.","If optional extraction is needed, wrap pop in a helper returning nil when empty."],"exampleFix":"// before\nmax = heap.pop  # raises 'куча пуста' when empty\n\n// after\nmax = heap.is_empty? ? nil : heap.pop","handlingStrategy":"validation","validationCode":"max = heap.pop unless heap.is_empty?","typeGuard":"def heap_nonempty?(h) = !h.is_empty?","tryCatchPattern":"begin\n  max = heap.pop\nrescue IndexError\n  max = nil\nend","preventionTips":["Guard extract-max with is_empty?.","Drive extract loops with `until heap.is_empty?`.","Track push/pop count for heaps used as priority queues."],"tags":["ruby","heap","priority-queue","empty-state","index-error"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}