{"record":{"id":"50e2aa0c2aa70eb6","repo":"krahets/hello-algo","slug":"error-50e2aa","errorCode":null,"errorMessage":"куча пуста","messagePattern":"куча пуста","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ru/codes/javascript/chapter_heap/my_heap.js","lineNumber":85,"sourceCode":"\n    /* Начиная с узла i, выполнить просеивание снизу вверх */\n    #siftUp(i) {\n        while (true) {\n            // Получение родительского узла для узла i\n            const p = this.#parent(i);\n            // Завершить heapify, когда «корневой узел уже пройден» или «узел не требует исправления»\n            if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;\n            // Поменять два узла местами\n            this.#swap(i, p);\n            // Циклическое просеивание вверх\n            i = p;\n        }\n    }\n\n    /* Извлечение элемента из кучи */\n    pop() {\n        // Обработка пустого случая\n        if (this.isEmpty()) throw new Error('куча пуста');\n        // Поменять корневой узел с самым правым листом местами (поменять первый и последний элементы)\n        this.#swap(0, this.size() - 1);\n        // Удаление узла\n        const val = this.#maxHeap.pop();\n        // Просеивание сверху вниз\n        this.#siftDown(0);\n        // Вернуть элемент с вершины кучи\n        return val;\n    }\n\n    /* Начиная с узла i, выполнить просеивание сверху вниз */\n    #siftDown(i) {\n        while (true) {\n            // Определить узел с максимальным значением среди i, l и r и обозначить его как ma\n            const l = this.#left(i),\n                r = this.#right(i);\n            let ma = i;\n            if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l;","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/ru/codes/javascript/chapter_heap/my_heap.js#L67-L103","documentation":"Thrown by MaxHeap.pop (JS, my_heap.js) with message 'куча пуста' ('heap is empty') when popping from an empty heap. pop swaps the root with the last leaf, removes the leaf, and sifts down — all meaningless on an empty structure, so the guard short-circuits.","triggerScenarios":"Calling pop() when #maxHeap.length === 0 (i.e., isEmpty() returns true). Common when draining a heap in a loop without checking size.","commonSituations":"Looping while(heap.size() >= 0) instead of > 0; popping more times than you pushed; using the heap as a priority queue that ran dry.","solutions":["Check isEmpty() before popping: while (!heap.isEmpty()) { const v = heap.pop(); }","Prefer peek() then pop() only when a value is expected.","If draining into an array, bound the loop by heap.size() captured once."],"exampleFix":"// before\nwhile (true) { const v = heap.pop(); } // eventually throws\n\n// after\nwhile (!heap.isEmpty()) { const v = heap.pop(); process(v); }","handlingStrategy":"validation","validationCode":"if (!heap.isEmpty()) { const v = heap.pop(); process(v); }","typeGuard":null,"tryCatchPattern":"try {\n  const v = heap.pop();\n} catch (e) {\n  if (e.message === 'куча пуста') { /* handle empty */ }\n  else throw e;\n}","preventionTips":["Always loop while (!heap.isEmpty()), never while (size >= 0).","Capture size once when draining: for (let n = heap.size(); n > 0; n--) heap.pop().","peek() does not throw on empty only if implemented; for this heap, guard pop explicitly."],"tags":["heap","javascript","precondition","empty-state","hello-algo"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}