5.1堆(heap)

堆(heap)

什么是堆?

  • 优先队列(Priority Queue) : 特殊的“队列”,取出的元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。

  • 操作:插入,删除

  • 优先队列的完全二叉树表示

  • 堆的两个特性

    • 结构性:用数组表示的完全二叉树
    • 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)
      • 最大堆,也称大顶堆:最大值
      • 最小堆,也称小顶堆:最小值
  • 注意:从根结点到任意结点路径上结点序列的有序性

堆的抽象数据类型描述

  • 类型名称:最大堆(MaxHeap)

  • 数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值

  • 操作集:最大堆H∈MaxHeap, 元素item∈ElementType, 主要操作有:

    MaxHeap Create( int MaxSize ):创建一个空的最大堆
    Boolean IsFull( MaxHeap H ):判断最大堆H是否已满
    Insert( MaxHeap H, ElementType item ): 将元素item插入最大堆H
    Boolean IsEmpty( MaxHeap H): 判断最大堆H是否为空
    ElementType DeleteMax( MaxHeap H):返回H中最大元素(高优先级)

最大堆的操作

1. 最大堆的创建
typedef struct HeapStruct *MaxHeap;
struct HeapStruct {
    ElementType *Elements; //存储堆元素的数组
    int Size; // 堆的目前元素个数
    int Capacity; // 堆的最大容量
};
MaxHeap Create( int MaxSize )
{ // 创建容量为MaxSize的空的最大堆
    MaxHeap H = malloc( sizeof( struct HeapStruct ));
    H->Elements = malloc( (MaxSize+1) * sizeof(ElementType));
    H->Size= 0;
    H->Capacity = MaxSize;
    H->Elements[0] = MaxData;
    //定义"哨兵"为大于堆的所有可能元素的值,便于以后更快操作
    return H;
}
2. 最大堆的插入
  • 算法:将新增结点插入到从其父结点到根结点的有序序列中
void Insert( MaxHeap H, ElementType item )
{
    //将元素item插入到最大堆H,其中H->Elements[0]已经定义为从哨兵
    int i;
    if(IsFull(H)){
        printf("最大堆已满")return;
        i = ++H->Size; //i指向插入后堆中的最后一个元素的位置
        for( ; H->Elements[i/2] < item; i/=2 )
            H->Elements[i] = H->Elements[i/2]; //向下过滤结点
        H->Elements[i] = item;//将item插入
    }
}

T(N) = O( log N)

最大堆的删除
  • 取出根结点(最大值)元素,同时删除堆的一个结点。
ElementType DeleteMax( MaxHeap H )
{
    // 从最大堆H中取出键值为最大的元素,并删除一个结点
    int Parent, Child;
    ElementType MaxItem, temp;
    if( IsEmpty(H) ) {
        printf("最大堆已为空");
        return;
    }
    MaxItem = H->Elements[1]; //取出根结点最大值
    //用最大堆中最后一个元素从根结点开始向上过滤下层结点
    temp = H->Elements[H->Size--];
    for( Parent=1; Parent*2<=H->Size; Parent = Child ) {
        Child = Parent*2;
        if( (Child!=H->Size)&&
          	(H->Elements[Child] < H->Elements[Child+1]))
            Child++;//Child指向左右子结点的较大者
        if( temp >= H->Elements[Child] ) break;
        else //移动temp元素到下一层
            H->Elements[Parent] = H->Elements[Child];
    }
    H->Elements[Parent] = temp;
    return MaxItem;
}
最大堆的建立
  • 建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中

    • 方法一:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中,其时间代价最大为O(NlogN)

    • 方法二:在线性时间复杂度下建立最大堆。
      1. 将N个元素按输入顺序存入,先满足完全二叉树的结构特性。
      2. 调整各结点位置,以满足最大堆的有序特性。

    • 建堆时间复杂性:O(n) 书中各结点的高度和

/*----------- 建造最大堆 -----------*/
void PercDown( MaxHeap H, int p )
{ /* 下滤:将H中以H->Data[p]为根的子堆调整为最大堆 */
    int Parent, Child;
    ElementType X;
 
    X = H->Data[p]; /* 取出根结点存放的值 */
    for( Parent=p; Parent*2<=H->Size; Parent=Child ) {
        Child = Parent * 2;
        if( (Child!=H->Size) && (H->Data[Child]<H->Data[Child+1]) )
            Child++;  /* Child指向左右子结点的较大者 */
        if( X >= H->Data[Child] ) break; /* 找到了合适位置 */
        else  /* 下滤X */
            H->Data[Parent] = H->Data[Child];
    }
    H->Data[Parent] = X;
}
 
void BuildHeap( MaxHeap H )
{ /* 调整H->Data[]中的元素,使满足最大堆的有序性  */
  /* 这里假设所有H->Size个元素已经存在H->Data[]中 */
 
    int i;
 
    /* 从最后一个结点的父节点开始,到根结点1 */
    for( i = H->Size/2; i>0; i-- )
        PercDown( H, i );
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值