大頂堆:任意非葉子節點的值大於等於其子節點的值。
小頂堆:任意非葉子節點的值小於等於其子節點的值。
堆是完全二叉樹,所以可以直接用數組存儲。
堆初始化:
堆的初始化使用篩降法,從最后一個非葉子節點開始向下調整直到跟節點。需要建堆的數組長度為n,最后一個元素的下標為n-1,其父節點為 ((n-1) - 1) >> 1
堆頂元素的刪除:
每次只能刪除堆頂元素,刪除完堆頂元素之后,將最后一個元素放在堆頂,此時的堆不滿足堆的性質,需要進行調整。
/** * 向下調整 * * @param i 要調整的編號 */ private void siftDown(int i) { // 如果父節點比任意一個子節點要大,需要調整,和子節點中較小的那個節點進行互換 // 只有非葉子節點才需要調整 int value = nums[i]; while (2 * i + 1 < len) { int left = 2 * i + 1; int right = 2 * i + 2; // 有右節點,先比較兩個左右節點 int minValueIdx = (right < len && nums[right] < nums[left]) ? right : left; // 子節點中比較小的和父節點比較 if (nums[minValueIdx] < value) { // 需要調整 nums[i] = nums[minValueIdx]; i = minValueIdx; } else { // 節點i比孩子節點都小,不用再調整了 break; } } nums[i] = value; }
向堆中添加元素:
每次向堆中添加元素時,直接將元素放在末尾,然后調整新放入元素的位置到正確的位置。
public void add(int i) { if (len < nums.length) { nums[len] = i; siftUp(len); len++; } } /** * 向上調整 * * @param i */ private void siftUp(int i) { // i = 0時是根節點, 不需要再調整了 int value = nums[i]; while (i > 0) { int p = (i - 1) >> 1; if (nums[p] > value) { // 父節點更大, 需要調整 nums[i] = nums[p]; i = p; } else { break; } } nums[i] = value; }