高薪算法+计算机职称考试数据结构和算法分析面试题

5.1 堆

2018-06-19  本文已影响2人  编程半岛

1. 什么是堆

优先队列:一种特殊的“队列”,取出元素的顺序是依照元素的优先权大小,而不是元素进入队列的先后顺序。
优先队列可用完全二叉树表示:

2. 堆的两个特性

结构性:用数组表示的完全二叉树
有序性:任意结点的关键字是其子树所有节点的最大值(最小值)


最大堆(MaxHeap):也称“大顶堆”:结点为最大值; 最大堆

最小堆(MinHeap):也称“小顶堆”:结点为最小值.

最小堆
注意:从根结点到任意结点路径上结点序列是有序的

3. 堆的抽象数据类型描述

类型名称:最大堆(MaxHeap)
数据对象集:完全二叉树, 每个结点的元素值不小于其子结点的元素值
操作集:最大堆H∈MaxHeap,元素item∈ElementType,主要操作有:
MaxHeap Create(int MaxSize):创建一个空的最大堆;
Boolean IsFull(MaxHeap H):判断最大堆H是否已满;
Boolean IsEmpty(MaxHeap H):判断最大堆H是否为空;
void Insert(ElementType item, MaxHeap H):将元素item插入最大堆H;
ElementType DeleteMax(MaxHeap H):返回(删除)H中最大元素(优先级最高的元素)。

4. 最大堆的操作

最大堆的结构:

typedef struct HeapStruct *MaxHeap;
struct HeapStruct{
    ElementType *Elements;    // 存储堆元素的数组
    int size;     // 堆的当前元素个数
    int capacity;    // 堆的最大容量
}; 

最大堆的创建:

MaxHeap Create(int MaxSize)
{
    MaxHeap H = MaxHeap malloc(sizeof( struct HeapStruct ));
    H->Elements = ElementType* malloc(sizeof( (MaxSize + 1) * ElementsType )); // 数组的第0号元素作为“哨兵”,堆的数据从数组的第1号元素开始存储
    H->Size = 0;
    H->Capacity = MaxSize;
    H->Element[0] = MaxData;  // 定义“哨兵”,MaxData大于堆中所有可能元素的值,便于以后更快操作
    return H;
}

最大堆的插入:
将新增结点插入到从其父结点到根结点的有序序列中。

// 将元素item插入最大堆H,其中H->Elements[0]已定义为哨兵
void Insert(ElementType item, MaxHeap)
{
    int i;
    if ( IsFull(H) )
    {
        printf("最大堆已满");
        return ;
    }
    i = ++H->size;    // 将i指向最大堆的最后一个元素位置
    while(H->Elements[i/2] < item)    // 将插入的item与堆中的序列计较并排序
    {
        H->Elements[i] = H->Elements[i/2];
        i /= 2;
    } 
    H->Elements[i] = item;  // 将item插入
}

最大堆的删除:
取出根结点(最大值)元素,同时删除堆的一个结点。


如图,将根结点58删除后,总共结点数量为4个,因此需要将第五号结点31移至第一号结点的。但是31<44,不满足最大堆的有序性规则,因此需要调序。调序方法:如果该结点小于其孩子,找出孩子中的最大值,然后交换,直到满足最大堆的有序性规则为止。
// 从最大堆中取出键值为最大的元素,并删除一个结点
ElementType DeleteMax(MaxHeap 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++;
        }
        if( temp >= H->Elements[Child] )
        {
            break;
        }
        else
        {
            H->Elements[Parent] = H->Elements[Child];
        }
    }
    H->Element[Parent] = temp;
    return MaxItem;
}

最大堆的建立:将已存在的N个元素按照最大堆的要求存放在一个一维数组中。
方法一:通过插入操作,将N个元素一个个相继插入到一个初始为空的堆中去,其时间复杂度为O(NlogN)。
方法二:在线性时间复杂度(O(N))下建立最大堆。

  1. 将N个元素按输入顺序存入,先满足完全二叉树的结构特征性
  2. 调整各结点位置,以满足最大堆的有序特性。(调整规则:从倒数一个有儿子的结点开始,调整为最大堆,直到根结点)


上一篇下一篇

猜你喜欢

热点阅读