堆 heap

来源:互联网 发布:手机淘宝怎么实名 编辑:程序博客网 时间:2024/06/05 04:31

堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的任务将等待很长时间才能结束,或者某些不短小,但具有重要性的作业,同样应当具有优先权。堆即为解决此类问题设计的一种数据结构。
逻辑定义
n个元素序列{k1,k2…ki…kn},当且仅当满足下列关系时称之为堆:
(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。
任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
二叉堆
二叉堆故名思议是一种特殊的堆,二叉堆具有堆的性质(父节点的键值总是大于或等于(小于或等于)任何一个子节点的键值),二叉堆又具有二叉树的性质(二叉堆是完全二叉树或者是近似完全二叉树)。当父节点的键值大于或等于(小于或等于)它的每一个子节点的键值时我们称它为最大堆(最小堆)。
完全二叉树是增加了限定条件的二叉树。假设一个二叉树的深度为n。为了满足完全二叉树的要求,该二叉树的前n-1层必须填满,第n层也必须按照从左到右的顺序被填满。
插入
新插入的节点new放在完全二叉树最后的位置,再和父节点比较。如果new节点比父节点小,那么交换两者。交换之后,继续和新的父节点比较…… 直到new节点不比父节点小,或者new节点成为根节点。
删除
让最后一个节点last成为新的节点,从而构成一个新的二叉树。再将last节点不断的和子节点比较。如果last节点比两个子节点中小的那一个大,则和该子节点交换。直到last节点不大于任一子节点都小,或者last节点成为叶节点。

以下C代码可以直接运行,有不妥当的地方望指正~

/*堆使用数组arr实现堆,arr[0]来存储堆的大小,从arr[1]开始存储元素构建的是小顶堆*/#include <stdio.h>void buildHeap(int *arr,int n);void insert(int *arr,int target);void bottom_up(int *arr);void top_down(int *arr);int  delete_root(int *arr);void heapSort(int *arr);/*arr:堆数组n: 要建的堆的长度*/void buildHeap(int *arr,int n){    int i=1;    for(;i<=n;i++)        insert(arr,arr[i]);}/*插入操作,把新插入的节点放在完全二叉树最后面的位置,然后开始自下而上的比较,如果新节点比其父节点小(小顶堆),那就进行交换;新的父节点在与其父节点进行比较...直到儿子节点大于父节点或者到达顶节点结束*//*arr: 堆数组target:要插入的元素*/void insert(int *arr,int target){    arr[0]++;    arr[arr[0]]=target;    bottom_up(arr);}void bottom_up(int *arr)//自下而上处理 从最后一个元素往上处理{    int nChild=arr[0];    int parent=nChild/2;    while(parent>0 && arr[nChild]<arr[parent])    {        arr[nChild]=arr[nChild]^arr[parent];        arr[parent]=arr[nChild]^arr[parent];        arr[nChild]=arr[nChild]^arr[parent];        nChild=parent;        parent=nChild/2;    }}/*删除操作:只能删除根节点,根节点删除后,会得到两个子树,需要进行重构堆,进行的操作为,让最后一个节点last成为根节点,然后进行向下比较,如果根节点大于其中一个儿子节点,则交换位置,直到父节点不大于儿子节点或到叶子为止。*/int  delete_root(int *arr){    if(arr[0]<1)        return -1;    int res=arr[1];    int nChild=arr[0];    arr[0]--;    arr[nChild]=arr[nChild]^arr[1];    arr[1]=arr[nChild]^arr[1];    arr[nChild]=arr[nChild]^arr[1];    top_down(arr);    return res;}void top_down(int *arr)//从第一个元素往下处理{    int nChild;    int parent=1;    nChild=parent<<1;    while(nChild<=arr[0])    {        if(nChild+1<=arr[0] && arr[nChild]>arr[nChild+1])            nChild++;        if(arr[parent]<=arr[nChild])            break;        arr[nChild]=arr[nChild]^arr[parent];        arr[parent]=arr[nChild]^arr[parent];        arr[nChild]=arr[nChild]^arr[parent];        parent=nChild;        nChild=parent<<1;    }}/*1.首先将待排序的元素构建二叉堆2.执行删除操作,并不真正删除,把头结点与尾节点交换,并形成新的堆3.重复步骤2*/void heapSort(int *arr)//堆排序{    int len=arr[0],i=arr[0];    while(--i)    {        delete_root(arr);    printf("arr[0]:%d\n",arr[0]);    }    arr[0]=len;}int main(int argc,char **args){    int arr[30]={0,9,88,23,45,9,100,200,230,234,453,12};    int i=0;    buildHeap(arr,10);    insert(arr,2);    for(i=0;i<=arr[0];i++)    {        printf("%d  ",arr[i]);    }    //printf("%d\n",delete_root(arr));    printf("\n");    heapSort(arr);    for(i=0;i<=arr[0];i++)    {        printf("%d  ",arr[i]);    }    printf("\n");    return 0;}
原创粉丝点击