zoukankan      html  css  js  c++  java
  • 什么是堆

    优先队列(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:	");
    103     for(i=1;i<H->Size;i++)
    104         printf("%d ", H->Data[i]);
    105     printf("
    ");
    106 }
    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    linux常用命令
    Hibernate常用API以及使用说明
    Hibernate使用套路,新手请进
    git 完全讲解 无废话,包含在myeclipse中使用,包括解决冲突
    Spring使用事务增加的注解实现方
    java.lang.ClassCastException: com.sun.proxy.$Proxy27 cannot be cast to com.bbk.n002.service.QuestionService
    使用aspectJ实现Spring AOP的两种方式
    用Diff和Patch工具维护源码
    opennebula 补丁制作与补丁升级
    IPMI总结
  • 原文地址:https://www.cnblogs.com/ch122633/p/8796660.html
Copyright © 2011-2022 走看看