堆的基础操作

声明:这里的堆是二叉堆,不是斜堆,左偏树,斐波那契堆之类的**东西(我都不会啊!!)

二叉堆,是一棵完全二叉树
树的根称为堆顶
一个节点的子树为空或一个堆

左儿子比右儿子小或大(怎么高兴怎么来)

左右儿子都比父亲大或小
堆顶最大称为大根堆
堆顶最小称为小根堆
如“图”,这是一个小根堆:
           1
         /     \
      2           3
    /    \      /     

3        4    4    

图很烂,不要介意

堆有4个基本操作:

插入,删除,取堆顶,合并

取堆顶简单,不说了

合并要把一个堆全放进另一个里

普通堆是nlogn的复杂度

所以一般用左偏树

由于我不会不想说就不说了

插入:

为了让堆保持完全二叉树的性质,比如我要插个0,操作如下

先把0插在最下面

           1
         /     \
      2           3
    /    \      /     \

3        4    4    0

然后发现不符合二叉堆性质

换一下

           1
         /     \
      2           3
    /    \      /     \

3        4   0       4

还是不行,再换

           1
         /     \
      2           0
    /    \      /     \

3        4    3     4

           0
         /     \
      2           1
    /    \      /     \

3        4    3     4

这就对了

时间复杂度为O(logn)

删除:

好,现在我要把0删了

为了不影响其他数,只有叶子结点可以直接删除

0是根,不能直接删

所以,换

           1
         /     \
      2           0
    /    \      /     \

3        4    3     4

           1
         /     \
      2           3
    /    \      /     \

3        4    0     4

           1
         /     \
      2           3
    /    \      /     \

3        4   4       0

这就可以删了

手打堆的代码太麻烦,本蒟蒻就懒得写了

STL:

priority_queue,优先队列,简称大根堆

push插入top堆顶pop删除堆顶

想用小根堆先变成负的再插,就行了

堆排序就是这样用的,全插进去再取出来

推荐几道题:

洛谷P3378,小根堆版子题,非常Easy

P1801黑匣子(有难度)

P2048,超级钢琴(谁愿做谁做,反正本蒟蒻完全不会)

P7078,贪吃蛇(要是做出来,恭喜你,可以进省队了)(CSP-S2020的题,我真F**K感谢CCF,提高组上黑题)

continue;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
最大堆排序的基本操作包括以下几个步骤: 1. 构建最大堆:将待排序的数组构造成一个最大堆。最大堆是一种满足父节点大于等于子节点的完全二叉树。构建最大堆的方法是从最后一个非叶子节点开始,依次向上调整每个节点,使其满足最大堆的性质。 2. 交换堆顶元素和最后一个元素:将最大堆的堆顶元素与最后一个元素交换位置,即将最大的元素放到数组的末尾。 3. 调整堆:将剩下的元素重新调整为最大堆。从堆顶开始,比较左右子节点的值,将较大的子节点与父节点交换位置,然后再对交换后的子节点进行调整,直到整个堆重新满足最大堆的性质。 4. 重复步骤2和步骤3,直到所有元素都被排序。 下面是一个用C++实现基于最大堆的堆排序的示例: ```cpp #include <iostream> using namespace std; // 调整堆 void adjustHeap(int arr[], int n, int i) { int largest = i; // 初始化最大值为根节点 int left = 2 * i + 1; // 左子节点 int right = 2 * i + 2; // 右子节点 // 如果左子节点大于根节点,更新最大值 if (left < n && arr[left] > arr[largest]) { largest = left; } // 如果右子节点大于根节点,更新最大值 if (right < n && arr[right] > arr[largest]) { largest = right; } // 如果最大值不是根节点,交换根节点和最大值 if (largest != i) { swap(arr[i], arr[largest]); // 递归调整交换后的子节点 adjustHeap(arr, n, largest); } } // 堆排序 void heapSort(int arr[], int n) { // 构建最大堆 for (int i = n / 2 - 1; i >= 0; i--) { adjustHeap(arr, n, i); } // 交换堆顶元素和最后一个元素,并调整堆 for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); adjustHeap(arr, i, 0); } } int main() { int arr[] = {91, 84, 72, 63, 55, 46, 37, 29, 20, 11}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); cout << "Sorted array: "; for (int i = 0; i < n; i++) { cout << arr[i] << " "; } cout << endl; return 0; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值