堆 之 Sift-up和Sift-down

 

1.sift-up

假定对于某个i>1,H[i]变成了键值大于它父节点键值的元素,这样就违反了堆的特性。我们需要使用Sift-up运算把新的数据项移到在二叉树中适合它的位置上。

Sift-up的运算沿着从H[i]到根节点的唯一一条路径,把H[i]移到适合它的位置上。在沿着路径的每一步上,都将H[i]键值和它父节点的键值H[⌊i/2⌋]相比较。

常用于:插入操作

代码:


void sift-up ( MaxHeap H)
{
    i = H->size;
    item = H->Element [i];
    for ( ; H -> Element [ i/2 ] < item; i /= 2 ) // 与父结点做比较,i / 2 表示的就是父结点的下标
        H -> Element [ i ] = H -> Element [ i/2 ]; // 向下过滤结点
    H -> Element [ i ] = item ; //若for循环完成后,i更新为父节点i,然后将 item 插入
}

放在堆的插入里就是: 


void Insert ( MaxHeap H,int item )
{
    // 将元素item插入最大堆H,其中H -> Elements [0] 已经定义为哨兵
    int i ;
    if ( H->Size ==1000 )
    {
        printf ( "最大堆已满" );
        return ;
    }
    i = ++H -> Size ; // i 指向插入后堆中的最后一个元素的位置
    for ( ; H -> Element [ i/2 ] < item; i /= 2 ) // 与父结点做比较,i / 2 表示的就是父结点的下标
        H -> Element [ i ] = H -> Element [ i/2 ]; // 向下过滤结点
    H -> Element [ i ] = item ; //若for循环完成后,i更新为父节点i,然后将 item 插入
    for(i = 1 ; i <= H->Size; i++)
    {
        printf("%d", H->Element[i]);
    }
    printf("\n");
}

2.Sift-down  

假定对于i ≤ ⌊n/2⌋,存储在H[i]中元素的键值变成小于H[2i]和H[2i+1]中的最大值(如果2i+1存在的话),这样也违反了堆的特性。Sift-down运算使H[i]“渗”到二叉树中适合它的位置上,沿着这条路径的每一步,都把H[i]的键值和存储在它子节点(如果存在)中的两个键值里最大的那个相比较。

 

过程  Sift-down

输入  数组H[1...n]和位于1和n之间的索引i

输出  下移H[i](如果需要),以使它不小于子节点

常用于删除操作,调整堆

 这里以我上篇博客为例,代码如下: 


sift-down(i)
{
    int  j, item;
    for(; i*2<=m ;i = j)
    {
        j = 2 * i;
        if(j!=m&&h[j]>h[j+1])
        {
            j++;
        }
        if(h[i]>h[j])
            swap(i, j);
        else
        {
            break;
        }
    }
}

删除代码为:(代码比较冗长,可以进行优化)

int DeleteMax( MaxHeap H )
{
    /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */
    int Parent, Child;
    int MaxItem, temp;
    if (H->Size == 0)
    {
        printf("最大堆已为空");
        return;
    }
    MaxItem = H->Element[1]; /* 取出根结点最大值 */
    /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
    H->Element[1] = H->Element[H->Size--];
    temp = H->Element[1];
    for( Parent=1; Parent*2<=H->Size; Parent=Child )
    {
        Child = Parent * 2;//child指向根下层元素的左节点
        if( (Child!= H->Size) &&
                (H->Element[Child] < H->Element[Child+1]) )
            Child++; //Child指向左右子结点的较大者
        if( temp >= H->Element[Child] ) break;//如果比较大的节点元素还大,就可以将temp元素放在树根
        else //移动temp元素到下一层
            swap(H, Parent,Child);//将儿子元素移到树根,temp再和下层元素作比较
    }
    int i;
    for(i = 1 ; i <= H->Size; i++)
    {
        printf("%d", H->Element[i]);
    }
    printf("\n");
    return MaxItem;
}

Sift-down  可以用于由数组建立堆(最小最大)

 详情请看我上一篇博客https://blog.csdn.net/Kaka_chake/article/details/81626385

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值