目录

  1. 什么是 Shift Down?
  2. Shift Down 的原理
  3. Shift Down 的实现
  4. Shift Down 的时间复杂度
  5. 应用场景
  6. 参考资料
  7. 出站链接

1. 什么是 Shift Down?

Shift Down(下沉)是一种用于堆的维护操作。它通常用于堆的删除操作,特别是当我们移除堆顶元素后,需要通过下沉操作来保持堆的性质。

具体来说,下沉操作会将堆顶元素(通常是最大堆或最小堆中的根元素)与其子节点交换,直到堆顶元素符合堆的性质。


2. Shift Down 的原理

假设我们操作的是最大堆

  1. 交换根节点与最后一个节点:首先,将堆的根节点与堆中的最后一个节点交换位置,然后删除最后一个节点。
  2. 下沉元素:从根节点开始,将交换后的节点与其子节点进行比较,选择较大的子节点,如果当前节点小于较大的子节点,则交换位置。继续下沉,直到节点到达合适的位置或没有子节点。

最大堆示例(删除堆顶元素):

      80
     /  \
   50    60
  /  \   /  \
30   40 45  20

删除堆顶元素 80,首先与最后一个元素交换:

      20
     /  \
   50    60
  /  \   /  \
30   40 45  80

然后进行下沉:

      60
     /  \
   50    45
  /  \   /  \
30   40 20  80

继续下沉:

      60
     /  \
   50    20
  /  \   /  \
30   40 45  80

最终,堆恢复了最大堆的性质。


3. Shift Down 的实现

PHP 代码实现

function shiftDown(&$heap, $index, $size) {
    while (2 * $index + 1 < $size) {
        $left = 2 * $index + 1;
        $right = 2 * $index + 2;
        $largest = $index;

        if ($left < $size && $heap[$left] > $heap[$largest]) {
            $largest = $left;
        }
        if ($right < $size && $heap[$right] > $heap[$largest]) {
            $largest = $right;
        }

        if ($largest == $index) {
            break;
        }

        // 交换
        list($heap[$index], $heap[$largest]) = [$heap[$largest], $heap[$index]];
        $index = $largest; // 继续向下
    }
}

function removeRoot(&$heap) {
    $size = count($heap);
    $heap[0] = $heap[$size - 1]; // 将根元素与最后一个元素交换
    array_pop($heap); // 删除最后一个元素
    shiftDown($heap, 0, $size - 1);
}

示例

$heap = [80, 50, 60, 30, 40, 45, 20];
removeRoot($heap);
print_r($heap);


Python 代码实现

def shift_down(heap, index, size):
    while 2 * index + 1 < size:
        left = 2 * index + 1
        right = 2 * index + 2
        largest = index

        if left < size and heap[left] > heap[largest]:
            largest = left
        if right < size and heap[right] > heap[largest]:
            largest = right

        if largest == index:
            break

        # 交换
        heap[index], heap[largest] = heap[largest], heap[index]
        index = largest  # 继续向下调整

def remove_root(heap):
    size = len(heap)
    heap[0], heap[-1] = heap[-1], heap[0]  # 将根元素与最后一个元素交换
    heap.pop()  # 删除最后一个元素
    shift_down(heap, 0, size - 1)

示例

heap = [80, 50, 60, 30, 40, 45, 20]
remove_root(heap)
print(heap)


4. Shift Down 的时间复杂度

在最坏情况下,Shift Down 需要将根节点下沉到堆的叶节点:

  • 堆的高度为 O(log n)
  • 每次下沉操作交换 O(1)

因此,Shift Down 的时间复杂度为 O(log n)


5. 应用场景

  • 删除堆顶元素:在优先队列中,堆顶元素通常是最小/最大元素,删除堆顶后需要进行 Shift Down 操作以保持堆的性质。
  • 堆排序:堆排序过程中,我们不断将堆顶元素移除,并使用下沉操作维护堆结构。
  • 实时数据流:维护动态的优先队列时,删除操作往往会涉及 Shift Down。

6. 参考资料

  1. 《算法导论》第 6 章 – 堆的基本操作
  2. LeetCode 题解:https://leetcode.cn/tag/heap/
  3. GeeksForGeeks Heap Operations: https://www.geeksforgeeks.org/binary-heap/

7. 出站链接