手写堆+堆排序

146 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

手写堆

操作

image.png

  1. 插入一个数
    1. 在堆的最后一个位置插入一个x,然后不断往上移up(size)
  2. 求集合中的最小值
    1. heap[1] :堆小根堆来说,堆顶元素,也就是第一个数一定是最小的
  3. 删除最小值
    1. 对小根堆来说,最小值就是堆顶,所以将最后一个数覆盖掉堆顶元素,然后堆顶元素往下down ()就行了
  4. 删除任意一个元素
    1. 假设删除的点是k的话,那么直接将最后一个元素将第k个点覆盖掉
    2. 然后根据大小情况,选择down还是up
    3. 或者不管,直接down一遍,然后up一遍就行了
  5. 修改任意一个元素
    1. 修改完之后,down一遍,up一遍就行了

堆的基本结构

堆是一棵完全二叉树:除了最后一层结点之外,其他层的结点都是满的,最后一层结点从左至右依次排布

小根堆的性质

每个点都是小于等于左右孩子的,根节点是树的最小值

堆的存储

image.png

  1. 用一个一维数组来存
    1. 1号点是根节点,下标从1开始的
    2. x的左儿子是:2x
    3. x的右儿子:2x + 1

堆的两个基本操作

  1. down(x)
    1. 往下调整
  2. up(x)
    1. 往上调整

down操作

// down操作
void down(int u)
{
    int t = u; // 用t来表示自己跟左右孩子,一共三个数中的最小值
    if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2; // 判断u跟左孩子的大小
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        // 将两个值交换一下
        swap(h[u], h[t]);
        down(t);
    }
}

up操作

void up(int u)
{
    while (u / 2 && h[u / 2] > h[u])
    {
        swap(h[u / 2], h[u]);
        u /= 2;
    }
}

堆排序

题目

www.acwing.com/problem/con… image.png

代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n, m;
int h[N], cnt; // h:heap  cnt:存当前heap存了多少个元素

// down操作
void down(int u)
{
    int t = u; // 用t来表示自己跟左右孩子,一共三个数中的最小值
    if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2; // 判断u跟左孩子的大小
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        // 将两个值交换一下
        swap(h[u], h[t]);
        down(t);
    }
    
}

void up(int u)
{
    while (u / 2 && h[u / 2] > h[u]) // 如果孩子比父亲还要小,针对小根堆,那么就要跟父亲换一下位置
    {
        swap(h[u / 2], h[u]);
        u /= 2;
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    
    for (int i = 1; i <= n; i++) scanf("%d", &h[i]);
    cnt = n;
    
    // 建堆过程,可以从n / 2开始down,时间复杂度是O(n)的
    for (int i = n / 2; i; i--) down(i);
    
    while (m--)
    {
        printf("%d ", h[1]); // 每次将当前堆顶元素输出
    	// 每输出一个数就要将堆顶元素删掉
        h[1] = h[cnt];
        cnt --;
        down(1);
    }
    
    return 0;
    
}