堆数据结构

堆数据结构

堆是一棵完全二叉树,通常用数组存储,满足父节点与子节点之间的优先级关系。常见的操作包括建堆、插入与删除堆顶元素。

建堆

堆可以通过逐个插入实现,也可以把一个无序数组当成堆底结构,自底向上依次向下调整以建立最大堆或最小堆。

插入

新元素先放到堆尾,再向上调整(父节点索引 (i-1)/2):如果子节点的值比父节点更大,就交换,直到堆性质恢复。

删除

默认只能直接删除堆顶。删除流程是把堆尾元素取代堆顶,再从上往下调整以恢复堆性质。如果想删除堆中间的某个元素,通常的做法是不断 pop() 弹出堆顶,遇到目标元素后再把弹出的值按原顺序重新插入。

代码(最大堆)

#include<iostream>
#include<vector>
using namespace std;

class MaxHeap{

    public:
    vector<int> heap;
    MaxHeap(vector<int>& nums){
        heap = nums;
        for(int i= nums.size()/2-1;i>=0;i--){
            tiao_zheng_down(i);
        }
    }

    void push(int num){
        heap.push_back(num);
        tiao_zheng_up();  // 插入新元素时,从堆尾向上调整
    }

    void pop(){
        swap(heap[0],heap[heap.size()-1]);
        heap.pop_back();
        tiao_zheng_down(0);
    }

    int top(){
        return heap[0];
    }

    void tiao_zheng_up(){
        int child_index = heap.size()-1;
        while(child_index>0){
            int parent_index = (child_index-1)/2;
            if(heap[child_index]>heap[parent_index]){
                swap(heap[child_index],heap[parent_index]);
                child_index = parent_index;
            }else{
                break;
            }
        }
    }

    void tiao_zheng_down(int index){
        while(true){
            int left_child = 2*index+1;
            int right_child = left_child+1;
            int real_index = index;
            if(left_child<heap.size()&&heap[left_child]>heap[real_index]){
                real_index = left_child;
            }
            if(right_child<heap.size()&&heap[right_child]>heap[real_index]){
                real_index = right_child;
            }
            if(real_index!=index){
                swap(heap[index],heap[real_index]);
                index = real_index;
            }else{
                break;
            }
        }
    }

};

int main(){
    vector<int> nums;
    MaxHeap maxHeap(nums);
    maxHeap.push(10);
    maxHeap.push(20);
    maxHeap.push(5);
    maxHeap.push(30);
    cout<<maxHeap.top()<<endl;

    maxHeap.pop();
    cout<<maxHeap.top()<<endl;

}

自定义结构体作为元素

如果需要按照结构体的某个字段排序,可以通过传入自定义的比较器。例如下面的 CompareTask 返回 true 时说明第一个参数优先级更低,于是 priority_queue 会把优先级大的放在前面,top() 始终返回当前最高优先级任务。

#include <iostream>
#include <queue>
#include <vector>

struct Task {
    int priority;
    std::string description;

    Task(int p, const std::string& desc) : priority(p), description(desc) {}
};

struct CompareTask {
    bool operator()(const Task& t1, const Task& t2) const {
        return t1.priority < t2.priority; // 优先级大的在前
    }
};

int main() {
    std::priority_queue<Task, std::vector<Task>, CompareTask> pq;

    pq.push(Task(5, "Write report"));
    pq.push(Task(1, "Fix critical bug"));
    pq.push(Task(3, "Attend meeting"));

    while (!pq.empty()) {
        Task t = pq.top();
        pq.pop();

        std::cout << "Processing task: " << t.description
                  << " with priority: " << t.priority << std::endl;
    }

    return 0;
}