数据结构(4) 堆

堆(Heap)是一种非常重要的数据结构,在优先队列、堆排序、图算法等领域有着广泛的应用。本文将详细介绍堆的概念、特性以及如何在C、Java和Python中实现堆。


一、堆的基本概念

堆是一种特殊的完全二叉树,它满足以下性质:

  1. 堆是一棵完全二叉树

  2. 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值

堆可以分为两种:

  • 最大堆(大顶堆):每个节点的值都大于或等于其子节点的值

  • 最小堆(小顶堆):每个节点的值都小于或等于其子节点的值


二、堆的存储方式

由于堆是完全二叉树,我们可以使用数组来高效地存储堆结构。对于数组中的任意一个位置i上的元素:

  • 其左子节点在位置:`2i + 1`
  • 其右子节点在位置:`2i + 2`
  • 其父节点在位置:`(i - 1) / 2`(整数除法)

三、堆的核心操作

堆的核心操作包括:

  1. 插入元素:将新元素添加到堆的末尾,然后向上调整(heapify up)

  2. 删除堆顶元素:将堆顶元素与末尾元素交换,删除末尾元素,然后向下调整(heapify down)

  3. 构建堆:将一个无序数组构建成堆


四、多语言实现

  1. C语言实现(最大堆)
cpp 复制代码
```c
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int *arr;
    int capacity;
    int size;
} MaxHeap;

MaxHeap* createHeap(int capacity) {
    MaxHeap* heap = (MaxHeap*)malloc(sizeof(MaxHeap));
    heap->capacity = capacity;
    heap->size = 0;
    heap->arr = (int*)malloc(capacity * sizeof(int));
    return heap;
}

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void heapifyUp(MaxHeap* heap, int index) {
    int parent = (index - 1) / 2;
    while (index > 0 && heap->arr[index] > heap->arr[parent]) {
        swap(&heap->arr[index], &heap->arr[parent]);
        index = parent;
        parent = (index - 1) / 2;
    }
}

void heapifyDown(MaxHeap* heap, int index) {
    int left = 2 * index + 1;
    int right = 2 * index + 2;
    int largest = index;
    
    if (left < heap->size && heap->arr[left] > heap->arr[largest]) {
        largest = left;
    }
    
    if (right < heap->size && heap->arr[right] > heap->arr[largest]) {
        largest = right;
    }
    
    if (largest != index) {
        swap(&heap->arr[index], &heap->arr[largest]);
        heapifyDown(heap, largest);
    }
}

void insert(MaxHeap* heap, int value) {
    if (heap->size == heap->capacity) {
        printf("Heap is full\n");
        return;
    }
    heap->arr[heap->size] = value;
    heapifyUp(heap, heap->size);
    heap->size++;
}

int extractMax(MaxHeap* heap) {
    if (heap->size == 0) {
        printf("Heap is empty\n");
        return -1;
    }
    int max = heap->arr[0];
    heap->arr[0] = heap->arr[heap->size - 1];
    heap->size--;
    heapifyDown(heap, 0);
    return max;
}

void buildHeap(MaxHeap* heap, int array[], int n) {
    for (int i = 0; i < n; i++) {
        insert(heap, array[i]);
    }
}

void printHeap(MaxHeap* heap) {
    for (int i = 0; i < heap->size; i++) {
        printf("%d ", heap->arr[i]);
    }
    printf("\n");
}

int main() {
    MaxHeap* heap = createHeap(10);
    int arr[] = {3, 2, 1, 5, 6, 4};
    buildHeap(heap, arr, 6);
    printf("Max heap: ");
    printHeap(heap);
    
    printf("Extracted max: %d\n", extractMax(heap));
    printf("Heap after extraction: ");
    printHeap(heap);
    
    insert(heap, 7);
    printf("Heap after inserting 7: ");
    printHeap(heap);
    
    free(heap->arr);
    free(heap);
    return 0;
}
  1. Java实现(最小堆)
java 复制代码
import java.util.Arrays;

public class MinHeap {
    private int[] heap;
    private int size;
    private int capacity;
    
    public MinHeap(int capacity) {
        this.capacity = capacity;
        this.size = 0;
        this.heap = new int[capacity];
    }
    
    private int parent(int index) {
        return (index - 1) / 2;
    }
    
    private int leftChild(int index) {
        return 2 * index + 1;
    }
    
    private int rightChild(int index) {
        return 2 * index + 2;
    }
    
    private void swap(int i, int j) {
        int temp = heap[i];
        heap[i] = heap[j];
        heap[j] = temp;
    }
    
    private void heapifyUp(int index) {
        while (index > 0 && heap[index] < heap[parent(index)]) {
            swap(index, parent(index));
            index = parent(index);
        }
    }
    
    private void heapifyDown(int index) {
        int minIndex = index;
        int left = leftChild(index);
        int right = rightChild(index);
        
        if (left < size && heap[left] < heap[minIndex]) {
            minIndex = left;
        }
        
        if (right < size && heap[right] < heap[minIndex]) {
            minIndex = right;
        }
        
        if (index != minIndex) {
            swap(index, minIndex);
            heapifyDown(minIndex);
        }
    }
    
    public void insert(int value) {
        if (size == capacity) {
            throw new IllegalStateException("Heap is full");
        }
        heap[size] = value;
        heapifyUp(size);
        size++;
    }
    
    public int extractMin() {
        if (size == 0) {
            throw new IllegalStateException("Heap is empty");
        }
        int min = heap[0];
        heap[0] = heap[size - 1];
        size--;
        heapifyDown(0);
        return min;
    }
    
    public void buildHeap(int[] array) {
        if (array.length > capacity) {
            throw new IllegalArgumentException("Array size exceeds heap capacity");
        }
        System.arraycopy(array, 0, heap, 0, array.length);
        size = array.length;
        
        for (int i = size / 2 - 1; i >= 0; i--) {
            heapifyDown(i);
        }
    }
    
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(heap, size));
    }
    
    public static void main(String[] args) {
        MinHeap heap = new MinHeap(10);
        int[] arr = {3, 2, 1, 5, 6, 4};
        heap.buildHeap(arr);
        System.out.println("Min heap: " + heap);
        
        System.out.println("Extracted min: " + heap.extractMin());
        System.out.println("Heap after extraction: " + heap);
        
        heap.insert(0);
        System.out.println("Heap after inserting 0: " + heap);
    }
}
  1. Python实现(最大堆)
python 复制代码
class MaxHeap:
    def __init__(self, capacity):
        self.capacity = capacity
        self.size = 0
        self.heap = [0] * capacity
    
    def parent(self, index):
        return (index - 1) // 2
    
    def left_child(self, index):
        return 2 * index + 1
    
    def right_child(self, index):
        return 2 * index + 2
    
    def swap(self, i, j):
        self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
    
    def heapify_up(self, index):
        while index > 0 and self.heap[index] > self.heap[self.parent(index)]:
            self.swap(index, self.parent(index))
            index = self.parent(index)
    
    def heapify_down(self, index):
        max_index = index
        left = self.left_child(index)
        right = self.right_child(index)
        
        if left < self.size and self.heap[left] > self.heap[max_index]:
            max_index = left
        
        if right < self.size and self.heap[right] > self.heap[max_index]:
            max_index = right
        
        if index != max_index:
            self.swap(index, max_index)
            self.heapify_down(max_index)
    
    def insert(self, value):
        if self.size == self.capacity:
            raise Exception("Heap is full")
        self.heap[self.size] = value
        self.heapify_up(self.size)
        self.size += 1
    
    def extract_max(self):
        if self.size == 0:
            raise Exception("Heap is empty")
        max_val = self.heap[0]
        self.heap[0] = self.heap[self.size - 1]
        self.size -= 1
        self.heapify_down(0)
        return max_val
    
    def build_heap(self, array):
        if len(array) > self.capacity:
            raise Exception("Array size exceeds heap capacity")
        self.size = len(array)
        self.heap = array.copy()
        
        for i in range(self.size // 2 - 1, -1, -1):
            self.heapify_down(i)
    
    def __str__(self):
        return str(self.heap[:self.size])

if __name__ == "__main__":
    heap = MaxHeap(10)
    arr = [3, 2, 1, 5, 6, 4]
    heap.build_heap(arr)
    print("Max heap:", heap)
    
    print("Extracted max:", heap.extract_max())
    print("Heap after extraction:", heap)
    
    heap.insert(7)
    print("Heap after inserting 7:", heap)

五、堆的应用场景

  1. 优先队列:堆是实现优先队列的理想数据结构

  2. 堆排序:利用堆进行排序,时间复杂度为O(nlogn)

  3. 图算法:如Dijkstra算法和Prim算法中用于高效获取最小/最大值

  4. 求Top K问题:维护一个大小为K的堆可以高效解决Top K问题

  5. 中位数查找:使用两个堆(最大堆和最小堆)可以高效查找中位数


六、堆的时间复杂度分析

  • 插入元素(insert):O(log n)

  • 删除堆顶元素(extract):O(log n)

  • 获取堆顶元素(peek):O(1)

  • 构建堆(buildHeap):

  • 通过逐个插入:O(n log n)

  • 使用Floyd算法:O(n)


七、总结

堆是一种高效的数据结构,特别适合需要频繁访问最大或最小元素的场景。通过本文的C、Java和Python实现,我们可以看到不同语言中堆的实现虽然语法不同,但核心逻辑是一致的。理解堆的原理和实现对于解决许多算法问题非常有帮助。

希望这篇文章能帮助你更好地理解堆数据结构。如果有任何问题,欢迎在评论区留言讨论!

相关推荐
罗技12316 分钟前
ES类的索引轮换
java·linux·elasticsearch
liaokailin1 小时前
Spring AI 实战:第十一章、Spring AI Agent之知行合一
java·人工智能·spring
JANYI20182 小时前
C文件在C++平台编译时的注意事项
java·c语言·c++
王禄DUT2 小时前
高维亚空间超频物质变压缩技术 第27次CCF-CSP计算机软件能力认证
数据结构·算法
蓝莓味柯基2 小时前
Python 学习路线与笔记跳转(持续更新笔记链接)
笔记·python·学习
benpaodeDD3 小时前
双列集合——map集合和三种遍历方式
java
唤醒手腕3 小时前
2025 年如何使用 Pycharm、Vscode 进行树莓派 Respberry Pi Pico 编程开发详细教程(更新中)
ide·python·pycharm
freyazzr3 小时前
Leetcode刷题 | Day51_图论03_岛屿问题02
数据结构·c++·算法·leetcode·深度优先·图论
reasonsummer3 小时前
【办公类-99-04】20250504闵豆统计表excle转PDF,合并PDF、添加中文字体页眉+边框下划线
python·pdf·deepseek
passionSnail3 小时前
《MATLAB实战训练营:从入门到工业级应用》工程实用篇-自动驾驶初体验:车道线检测算法实战(MATLAB2016b版)
算法·matlab·自动驾驶