什么是堆

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

 

堆的两个特性

结构性:用数组表示的完全二叉树。

有序性:任一结点的关键字是其子树所有结点的最大值(或最小值)

  • “最大堆(MaxHeap)”,也称“大顶堆”:最大值
  • “最小堆(MinHeap)”,也称“小顶堆”:最小值

 

堆的抽象数据类型描述

类型名称:最大堆(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中最大元素(高优先级)

 

最大堆的创建

typedef struct HNode *Heap; /* 堆的类型定义 */
struct HNode {
    ElementType *Data; /* 存储元素的数组 */
    int Size;          /* 堆中当前元素个数 */
    int Capacity;      /* 堆的最大容量 */
};
typedef Heap MaxHeap; /* 最大堆 */
typedef Heap MinHeap; /* 最小堆 */

创建一个空的最大堆

#define MAXDATA 1000  /* 该值应根据具体情况定义为大于堆中所有可能元素的值 */
 
MaxHeap CreateHeap( int MaxSize )
{ /* 创建容量为MaxSize的空的最大堆 */
 
    MaxHeap H = (MaxHeap)malloc(sizeof(struct HNode));
    H->Data = (ElementType *)malloc((MaxSize+1)*sizeof(ElementType));
    H->Size = 0;
    H->Capacity = MaxSize;
    H->Data[0] = MAXDATA; /* 定义"哨兵"为大于堆中所有可能元素的值*/
 
    return H;
}

 

将item插入到堆H中

bool IsFull( MaxHeap H )
{
    return (H->Size == H->Capacity);
}
 
bool Insert( MaxHeap H, ElementType X )
{ /* 将元素X插入最大堆H,其中H->Data[0]已经定义为哨兵 */
    int i;
  
    if ( IsFull(H) ) { 
        printf("最大堆已满");
        return false;
    }
    i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */
    for ( ; H->Data[i/2] < X; i/=2 )
        H->Data[i] = H->Data[i/2]; /* 上滤X */
    H->Data[i] = X; /* 将X插入 */
    return true;
}
 
#define ERROR -1 /* 错误标识应根据具体情况定义为堆中不可能出现的元素值 */

 插入到最后一个位置,如果不符合,就和父结点换位置。如果继续不符合就继续和父结点换位置,直到符合。

 

最大堆的删除

bool IsEmpty( MaxHeap H )
{
    return (H->Size == 0);
}
 
ElementType DeleteMax( MaxHeap H )
{ /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */
    int Parent, Child;
    ElementType MaxItem, X;
 
    if ( IsEmpty(H) ) {
        printf("最大堆已为空");
        return ERROR;
    }
 
    MaxItem = H->Data[1]; /* 取出根结点存放的最大值 */
    /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */
    X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */
    for( Parent=1; 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;
 
    return MaxItem;
} 

 

 

最大堆的建立

建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中

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

方法2:在线性事件复杂度下建立最大堆

(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性

(2)调整各结点位置,以满足最大堆的有序特性

/*----------- 建造最大堆 -----------*/
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 );
}

 

 最小堆相关的代码,和最大堆的类似

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 
  5 #define MINDATA -1000
  6 #define ERROR -1
  7 typedef struct HeapStruct *MinHeap;
  8 struct HeapStruct {
  9     int *Data;      /* 存储元素数组 */
 10     int Size;       /* 堆中当前元素个数 */
 11     int Capacity;   /* 堆的最大容量 */
 12 };
 13 
 14 MinHeap CreateHeap(int MaxSize)
 15 {
 16     MinHeap H = (MinHeap)malloc(sizeof(struct HeapStruct));
 17     H->Data = (int *)malloc((MaxSize+1)*sizeof(int));
 18     H->Size = 0;
 19     H->Capacity = MaxSize;
 20     H->Data[0] = MINDATA;           /* 定义"哨兵"为大于堆中所有可能元素的值*/
 21 
 22     return H;
 23 }
 24 
 25 int IsFull(MinHeap H)
 26 {
 27     return (H->Size == H->Capacity);
 28 }
 29 
 30 int Insert(MinHeap H, int X)
 31 {
 32     int i;
 33     if(IsFull(H)) {
 34         printf("MinHeap full");
 35         return ERROR;
 36     }
 37     i = ++H->Size;          /* i指向插入后堆中的最后一个元素的位置 */
 38     for(;H->Data[i/2]>X;i=i/2)
 39         H->Data[i] = H->Data[i/2];  /* 上滤X */
 40     H->Data[i] = X;     /* 将X插入 */
 41     return 0;
 42 }
 43 
 44 int IsEmpty(MinHeap H)
 45 {
 46     return (H->Size == 0);
 47 }
 48 
 49 int DeleteMin(MinHeap H)
 50 {
 51     int Parent, Child;
 52     int MinItem, X;
 53 
 54     if(IsEmpty(H)) {
 55         printf("MinHeap Empty");
 56         return ERROR;
 57     }
 58 
 59     MinItem = H->Data[1];       //第一个元素
 60     X = H->Data[H->Size--];     //最后一个元素
 61     for(Parent=1;Parent*2<=H->Size;Parent=Child) {
 62         Child = Parent*2;
 63         if((Child!=H->Size)&&(H->Data[Child]>H->Data[Child+1]))
 64             Child++;
 65         if(X <= H->Data[Child]) break;
 66         else
 67             H->Data[Parent] = H->Data[Child];
 68     }
 69     H->Data[Parent] = X;
 70 
 71     return MinItem;
 72 }
 73 
 74 void PercDown(MinHeap H, int p)
 75 {
 76     int Parent, Child;
 77     int X;
 78 
 79     X = H->Data[p];     /* 取出根结点存放的值 */
 80     for(Parent=p;Parent*2<=H->Size;Parent=Child) {
 81         Child = Parent * 2;
 82         if((Child!=H->Size)&&(H->Data[Child]>H->Data[Child+1]))
 83             Child++;        /* Child指向左右子结点的较小者 */
 84         if(X <= H->Data[Child]) break;  /* 找到了合适位置 */
 85         else        /* 下滤X */
 86             H->Data[Parent] = H->Data[Child];
 87     }
 88     H->Data[Parent] = X;
 89 }
 90 
 91 void BuildHeap(MinHeap H)
 92 {
 93     int i;
 94     /* 从最后一个结点的父节点开始,到根结点1 */
 95     for(i=H->Size/2;i>0;i--)
 96         PercDown(H, i);
 97 }
 98 
 99 void Print(MinHeap H)
100 {
101     int i;
102     printf("H:\t");
103     for(i=1;i<H->Size;i++)
104         printf("%d ", H->Data[i]);
105     printf("\n");
106 }

 

posted @ 2018-04-13 13:44  习惯就好233  阅读(342)  评论(0编辑  收藏  举报