{"record":{"id":"d9ec2d1318bd70d9","repo":"krahets/hello-algo","slug":"heap-is-empty-d9ec2d","errorCode":null,"errorMessage":"Heap is empty.","messagePattern":"Heap is empty\\.","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"zh-hant/codes/typescript/chapter_heap/my_heap.ts","lineNumber":84,"sourceCode":"\n    /* 從節點 i 開始，從底至頂堆積化 */\n    private siftUp(i: number): void {\n        while (true) {\n            // 獲取節點 i 的父節點\n            const p = this.parent(i);\n            // 當“越過根節點”或“節點無須修復”時，結束堆積化\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    public pop(): number {\n        // 判空處理\n        if (this.isEmpty()) throw new RangeError('Heap is empty.');\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    private siftDown(i: number): void {\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":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/zh-hant/codes/typescript/chapter_heap/my_heap.ts#L66-L102","documentation":"A RangeError 'Heap is empty.' thrown by pop() in MaxHeap (my_heap.ts:84). pop() swaps the root with the last leaf, removes the tail, then sifts the new root down; on an empty heap there is nothing to swap or return, so the guard refuses the operation. peek() is NOT guarded, so it would return undefined on empty — pop is the only method that throws here.","triggerScenarios":"Calling maxHeap.pop() when maxHeap.size() === 0 (i.e., maxHeap.isEmpty() is true). This happens when draining a heap in a loop and popping one more time than the number of elements, or calling pop on a freshly constructed `new MaxHeap()` with no initial array.","commonSituations":"Off-by-one in a while-pop loop (using `while (true)` or `<= size` instead of `while (!heap.isEmpty())`); popping after a previous pop already emptied the heap; treating peek()'s undefined as 'still has data' and then popping; draining a heap built from an empty or undefined input array.","solutions":["Guard every pop with `if (!heap.isEmpty()) heap.pop()` or loop with `while (!heap.isEmpty())`.","Call isEmpty() (or size() === 0) before pop rather than relying on peek().","Track the count you pushed and pop at most that many times.","If a sentinel/undefined result is acceptable, wrap pop in a helper that returns undefined on empty."],"exampleFix":"// before: off-by-one pops the empty heap and throws\nwhile (heap.size() >= 0) {\n    heap.pop();\n}\n\n// after: stop when empty\nwhile (!heap.isEmpty()) {\n    const top = heap.pop();\n}","handlingStrategy":"validation","validationCode":"// Never pop an empty heap\nfunction safePop(heap: MaxHeap): number | undefined {\n    return heap.isEmpty() ? undefined : heap.pop();\n}\n// usage:\nwhile (!heap.isEmpty()) {\n    const top = heap.pop();\n}","typeGuard":"// Heap exposes isEmpty(); treat it as the emptiness guard\nconst hasElements = (heap: MaxHeap): boolean => !heap.isEmpty();","tryCatchPattern":"try {\n    const top = heap.pop();\n} catch (e) {\n    if (e instanceof RangeError && /Heap is empty/.test(e.message)) {\n        // nothing to pop; handle empty state\n    } else throw e;\n}","preventionTips":["Always loop with `while (!heap.isEmpty())`, not a fixed or `>= 0` bound.","peek() is NOT guarded and returns undefined on empty — do not use it to test for data.","Track the count of pushes and pop at most that many times.","When draining, prefer isEmpty() over comparing size() to a cached number."],"tags":["typescript","heap","max-heap","empty-collection","range-error"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}