7-1 堆的操作

编写代码,实现最小堆(Min-Heap)的操作。

输入格式:

第一行是两个不大于1000的正整数NK,用空格间隔。其中N是堆的容量,需创建一个容量为N的堆。

接下来K行,是对这个堆的依次的K项插入或删除操作:用 1 x 表示插入元素x;用 -1 表示删除堆顶。

接下来一行是一个不大于1000的正整数M

接下来一行是M个整数(在整型范围内),用空格间隔,

要求将这M个整数组成的列表调整为一个最小堆。

输出格式:

对于第一个堆的K项操作,每次操作后,在一行中依次序打印堆元素,元素间使用1个空格分隔;

对于第二个堆,在调整完成后,在一行中依次序打印堆元素,元素间使用1个空格分隔。

输入样例:

10 8
1 1
1 2
1 3
1 4
1 5
-1
1 6
-1
8
1 2 3 4 5 6 7 8

输出样例:

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
2 4 3 5
2 4 3 5 6
3 4 6 5
1 2 3 4 5 6 7 8

代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB

思路:

写一个最小堆类,然后通过成员函数进行增删查改
四个私有成员变量和八个公有成员函数。私有成员变量分别是:

  • data:一个动态数组,用来存储堆元素
  • capacity:一个整数,表示堆的最大容量
  • size:一个整数,表示堆的当前大小
  • swap:一个函数,用来交换两个整数的值
    公有成员函数分别是:
  • 构造函数:用来初始化堆的容量和大小,并预分配空间
  • isEmpty:用来判断堆是否为空,返回布尔值
  • isFull:用来判断堆是否已满,返回布尔值
  • insert:用来插入一个元素到堆中,如果堆已满,返回false,否则返回true,并调用siftUp函数来向上调整堆
  • removeMin:用来删除堆顶的元素,如果堆为空,返回false,否则返回true,并调用siftDown函数来向下调整堆
  • print:用来打印堆中的元素,用空格分隔
  • heapify:用来将一个数组调整为一个最小堆,参数为数组指针和数组长度,先清空原有的堆元素,然后将数组元素复制到堆中,再从最后一个非叶子结点开始向下调整堆
  • siftUp:用来向上调整堆,使其满足最小堆性质,参数为一个整数,表示要调整的结点的索引,从该结点开始,沿着其父结点不断上移,直到找到合适的位置或者到达根结点为止
  • siftDown:用来向下调整堆,使其满足最小堆性质,参数为一个整数,表示要调整的结点的索引,从该结点开始,沿着其左右子结点中较小的一个不断下移,直到找到合适的位置或者到达叶结点为止

代码如下:

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

// 定义一个最小堆类
class MinHeap {
private:
    vector<int> data; // 用一个动态数组存储堆元素
    int capacity; // 堆的最大容量
    int size; // 堆的当前大小

    // 向上调整堆,使其满足最小堆性质
    void siftUp(int i) {
        while (i > 0) {
            int parent = (i - 1) / 2; // 父节点的索引
            if (data[i] < data[parent]) { // 如果当前节点比父节点小,交换它们
                swap(data[i], data[parent]);
                i = parent; // 更新当前节点的索引
            }
            else {
                break; // 如果当前节点不比父节点小,说明已经满足最小堆性质,退出循环
            }
        }
    }

    // 向下调整堆,使其满足最小堆性质
    void siftDown(int i) {
        while (i < size) {
            int left = 2 * i + 1; // 左孩子的索引
            int right = 2 * i + 2; // 右孩子的索引
            int min = i; // 最小值的索引,初始为当前节点
            if (left < size && data[left] < data[min]) { // 如果左孩子存在且比当前节点小,更新最小值的索引
                min = left;
            }
            if (right < size && data[right] < data[min]) { // 如果右孩子存在且比当前节点小,更新最小值的索引
                min = right;
            }
            if (min != i) { // 如果最小值不是当前节点,交换它们
                swap(data[i], data[min]);
                i = min; // 更新当前节点的索引
            }
            else {
                break; // 如果最小值是当前节点,说明已经满足最小堆性质,退出循环
            }
        }
    }

public:
    // 构造函数,初始化堆的容量和大小
    MinHeap(int cap) {
        capacity = cap;
        size = 0;
        data.reserve(capacity); // 预分配空间,避免频繁扩容
    }

    // 判断堆是否为空
    bool isEmpty() {
        return size == 0;
    }

    // 判断堆是否已满
    bool isFull() {
        return size == capacity;
    }

    // 插入一个元素到堆中,如果堆已满,返回false,否则返回true
    bool insert(int x) {
        if (isFull()) {
            return false;
        }
        data.push_back(x); // 将元素添加到数组末尾
        size++; // 增加堆的大小
        siftUp(size - 1); // 从最后一个节点开始向上调整堆
        return true;
    }

    // 删除堆顶的元素,如果堆为空,返回false,否则返回true
    bool removeMin() {
        if (isEmpty()) {
            return false;
        }
        data[0] = data[size - 1]; // 将最后一个元素覆盖堆顶元素
        data.pop_back(); // 删除最后一个元素
        size--; // 减少堆的大小
        siftDown(0); // 从根节点开始向下调整堆
        return true;
    }

    // 打印堆中的元素,用空格分隔
    void print() {
        for (int i = 0; i < size; i++) {
            if(i==size-1){
                cout<<data[i];
            }
            else{
                cout << data[i] << " ";
            }
            
        }
        cout << endl;
    }

    // 将一个数组调整为一个最小堆,参数为数组指针和数组长度
    void heapify(int* arr, int n) {
        data.clear(); // 清空原有的堆元素
        data.insert(data.end(), arr, arr + n); // 将数组元素复制到堆中
        size = n; // 更新堆的大小
        for (int i = (size - 2) / 2; i >= 0; i--) { // 从最后一个非叶子节点开始向下调整堆
            siftDown(i);
        }
    }
};

// 主函数,用于测试
int main() {
    int N, K, M; // 输入的参数
    cin >> N >> K; // 读入堆的容量和操作次数
    MinHeap heap(N); // 创建一个容量为N的最小堆
    for (int i = 0; i < K; i++) { // 循环读入K次操作
        int op; // 操作类型
        cin >> op; // 读入操作类型
        if (op == 1) { // 如果是插入操作
            int x; // 插入的元素
            cin >> x; // 读入插入的元素
            heap.insert(x); // 调用堆的插入方法
        }
        else if (op == -1) { // 如果是删除操作
            heap.removeMin(); // 调用堆的删除方法
        }
        heap.print(); // 打印堆中的元素
    }
    cin >> M; // 读入数组的长度
    int* arr = new int[M]; // 动态分配数组空间
    for (int i = 0; i < M; i++) { // 循环读入M个数组元素
        cin >> arr[i];
    }
    heap.heapify(arr, M); // 调用堆的调整方法,将数组转换为最小堆
    heap.print(); // 打印堆中的元素
    delete[] arr; // 释放数组空间
    return 0;
}

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Haru_Yuki

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值