堆 heap

堆是一种特殊的数据结构,常用于解决优先级队列的问题。本文介绍了堆的逻辑定义、性质,特别是二叉堆的概念,包括最大堆和最小堆。此外,详细阐述了堆的插入和删除操作,并提供了一个简单的C代码实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

堆(英语: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;
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值