📜  堆数据结构(1)

📅  最后修改于: 2023-12-03 15:08:08.802000             🧑  作者: Mango

堆数据结构

堆是一种基于树的数据结构,可以用数组实现。它的一个重要应用是用来实现优先队列。 堆是一个完全二叉树,且满足堆特性:对于一颗以 i 为根的子树,要么这颗子树为空,要么满足以下条件:

  • 如果 i 有左子节点,则左子节点的值小于等于 i 的值。
  • 如果 i 有右子节点,则右子节点的值小于等于 i 的值。

堆有两种类型:最大堆和最小堆。

在最大堆中,根节点的值最大,每个子节点的值都小于等于它的父节点的值。

在最小堆中,根节点的值最小,每个子节点的值都大于等于它的父节点的值。

实现

堆可以使用数组来实现,因为堆的结构可以看作树形结构的一个数组,每个节点在数组中的下标满足以下规则:

  • 以 0 为根节点,左子节点下标为 1,右子节点下标为 2;
  • 以 1 为根节点,左子节点下标为 3,右子节点下标为 4;
  • 以 2 为根节点,左子节点下标为 5,右子节点下标为 6;
  • 以 i 为根节点,左子节点下标为 2i+1,右子节点下标为 2i+2。

可以通过数组实现堆的插入和删除操作。

插入操作

插入操作通常是将新元素添加到堆的底部,然后一直交换它与它的父节点,直到满足堆的特性。伪代码如下:

Insert(heap, x):
    heap.add(x)
    i = heap.length - 1
    while i > 0 and heap[i] > heap[parent(i)]:
        swap(heap[i], heap[parent(i)])
        i = parent(i)
删除操作

删除操作通常是将堆的根节点删除并将堆的底部元素替换为根,然后一直交换它与它的子节点,直到满足堆的特性。伪代码如下:

Delete(heap):
    if heap.length == 0:
        throw error "Heap is empty"
    
    max = heap[0]
    last = heap[-1]
    heap.pop()
    
    if heap.length > 0:
        heap[0] = last
        heapify(heap, 0)
    
    return max

heapify(heap, i):
    left = 2*i + 1
    right = 2*i + 2
    largest = i
    
    if left < heap.length and heap[left] > heap[largest]:
        largest = left
    
    if right < heap.length and heap[right] > heap[largest]:
        largest = right
    
    if largest != i:
        swap(heap[i], heap[largest])
        heapify(heap, largest)
应用

堆最常见的应用是实现优先队列。使用堆作为优先队列的底层数据结构可以实现 O(log n) 的插入和删除操作,因此在需要频繁插入和删除元素的场合非常有效。

除了优先队列,堆还有其他一些应用,如求 Top k 问题、排序等。

总结

堆是一种非常重要的基础数据结构,可以用来实现优先队列等许多应用。它的操作并不复杂,但需要对其特性和实现方法有清晰的认识。