堆以及我的理解

        首先,堆是将一个个元素以完全二叉树的分布形式储存起来,因此,在保证每一个元素(x)的左结点(2x)和右结点(2x+1)都比自身小的情况下,就可以实现最基本的排序,由此进行对堆的其他操作。

初始定义值:

const int N=1000010;
int h[N],ph[N],hp[N],size,m;

h储存每个位置的值,ph和hp用来保证两个元素位置交换时自身插入次序的不变,size用来代表当前使用的,下一个将要插入的新值的位置,也就是二叉树的最下层的最右边。可以理解为size记录h的位置,m记录ph、hp的位置。

关键模板:

一:

void heap_swap(int a,int b)
{
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a],hp[b]);
    swap(h[a],h[b]);
}

堆所用到的专属交换函数,通过两组额外数组使得a与b的插入次序最终不变,然后交换数值。

二:

void down(int u)
{
    int t=u;
    if(u*2<=size&&h[u*2]<h[t]) t=u*2;
    if(u*2+1<=size&&h[u*2+1]<h[t]) t=u*2+1;
    if(u!=t)
    {
        heap_swap(u,t);
        down(t);
    }
}

向下处理,先用t存入u,判断u的左结点是否存在以及是否比t的值小,是则用t存入左结点,再判断右结点是否存在以及比较大小,最后判断t是否与u相等,这样就可以实现u与其左、右结点中较小值交换,然后反复进行“向下操作”,知道u在一且不大于它的值下面。

三:

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

当u的上位结点存在数值比自身大时,与之交换,一直重复至条件不符时。

---------------------------------------------------------------------------------------------------------------------------------堆中常见操作:

一、插入一个数:

cin>>x;
size++;
m++;
ph[m]=size,ph[size]=m;
h[size]=x;
up(size);

正常的赋值与向上操作。 

二、求集合中当前最小值:

cout<<h[1];

根据以上操作,作为根结点的第一个值就是最小值。 

三、删除最小值:

heap_swap(1,size)
size--;
down(1);

先用最后的值覆盖掉第一个值,再对第一个值进行向下操作。

四、删除第k个值:

heap_swap(k,size);
size--;
down(k),up(k);

与删最小值相似,因为不确定第k个值与末值孰大孰小,所以无脑down+up。

五、修改第k个值:

h[k]=x;
down(k),up(k);

与上同理。

当“第k个值”变为“第k个插入的值”时,只需在前面加上k=ph[k]。

--------------------------------------------------------------------------------------------------------------------------------以上便是我认识的关于堆的知识。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值