【每日一题】堆的任意位置的调整

文章目录

在这里插入图片描述

题目描述


以插入的方式来建堆实际上是O(NlogN),而O(N)的建堆方式就是向下调整算法完成的。
堆排序算法描述及时间复杂度分析

h的话就是heap堆,size就是当前存了多少个元素,指向下一个可以存放的位置。
ph存储的是插入的第k个数以及对应在h数组当中下标的映射;
hp存储的是堆里面的每一个点是第k个元素。

删除一个任意位置的元素,如果已经定位到该元素的位置,那么只需要swap(a[i],a[size]),然后将a[i]这个位置的元素进行向上或者向下调整,因为交换过后的元素可能比当前元素大也可能比当前元素小,但是走向上调整或者向下调整一遍就能得到答案。
修改的操作也是如此。直接修改当前元素,然后向上或者向下调整。

  • n 就是一直在增大,ph数组不会往回头看,因为k是不断增大的。
  • _size 就是最后一个元素
  • ph的下标标识当前节点是第k个插入的元素,ph中的元素不会被覆盖,并且由于k是不断增大的,所以ph数组会一直往后走。
  • hp数组是堆当中的元素到ph的映射,由于增删改,所以hp当中的元素就会一直发生变化(hp.size() == h.size())。但只需要当前元素能够找到对应ph的下标即可,得知自己是第k个元素插入的即可。(这个是交换元素的需求,因为两个元素交换的时候也需要更改ph表,标识插入的次序的改变)。
    在这里插入图片描述
    ph的下标就是第K+1个插入的元素,如0位置就是第一个。

在这里插入图片描述

每一次调整都是需要heap_swap,维护三个数组的关系。

题解


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

const int N = 100010;
int h[N];
int hp[N];//heap -> p
int ph[N];//p -> heap
int _size = 0;//遍历到第几个元素
void heap_swap(int parent, int child)
{
    swap(ph[hp[parent]], ph[hp[child]]);
    swap(hp[parent], hp[child]);
    swap(h[parent], h[child]);
}

void AdjustUp(int child)//key标识元素
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (h[parent] > h[child])
        {
            heap_swap(parent, child);
            child = parent;
            parent = (child - 1) / 2;
        }
        else break;
    }

}
//小堆
void AdjustDown(int parent)
{
    int child = parent * 2 + 1;
    while (child < _size)
    {
        if (child + 1 < _size && h[child] > h[child + 1])
        {
            child++;
        }
        if (h[parent] > h[child])
        {
            heap_swap(parent, child);
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}
int main()
{
    int m;
    cin >> m;
    int n = 0;
    while (m--)
    {
        string str;
        cin >> str;
        if (str == "I")
        {
            int k;
            cin >> k;
            int child = _size;
            h[child] = k;
            ph[n] = _size;
            hp[_size] = n;
            AdjustUp(_size);
            ++_size;
            ++ n;
        }
        else if (str == "PM")
        {
            cout << h[0] << endl;
        }
        else if (str == "DM")
        {
            heap_swap(0,_size - 1);
            _size--;
            AdjustDown(0);
        }
        else if (str == "D")
        {
            int k;
            cin >> k;
            k = ph[k - 1];
            heap_swap(k, _size - 1);
            --_size;
            AdjustUp(k);
            AdjustDown(k);
        }
        else
        {
            int k, x;
            cin >> k >> x;
            k = ph[k - 1];
            h[k] = x;
            AdjustDown(k);
            AdjustUp(k);
        }
    }
    return 0;
}



end

  • 喜欢就收藏
  • 认同就点赞
  • 支持就关注
  • 疑问就评论
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

^jhao^

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

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

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

打赏作者

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

抵扣说明:

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

余额充值