算法精解----14、堆

本文介绍了二叉堆数据结构的基本概念,包括其用途、节点编号规则、数据结构定义及其实现方法。详细阐述了如何通过数组实现二叉堆,并提供了插入元素、删除元素等关键操作的具体步骤。

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

1、用途:快速找到最大或最小元素,每一层的父节点始终大于或小于左右节点,左右节点之间没有关系。最底层最右端的节点就是最后一个节点。

2、节点成S行自上而下,自左向右顺序编号。元素对应在数组当中。若父节点编号为n,那么左右节点分别为2n+1,2n+2。可以随机访问,虽然属于二叉树,但是不用指针把每个节点串起来体现节点之间的关系。

有些定义放在xxxx.c中说明他们不是公共接口,可以访问的公共接口放在xxxx.h文件中。

3、数据结构

typedef struct _HEAP_H{
    int size;
    void **tree;
    void (*destroy)(void *data);
    int (*compare)(void *key1, void *key2);
}Heap;

4、初始化堆,释放堆

void heap_init(Heap *tree, void (*destroy)(void *data), int (*compare)(void *key1, void *key2))
{
    tree->size = 0;
    tree->tree = NULL;
    tree->destroy = destroy;
    tree->compare = compare;
    return;
}

void heap_destroy(Heap *tree)
{
    int i;
    if(tree->destroy != NULL)
    {
        for(i = 0; i < heap_size(tree); i++)
        {
            tree->destroy(tree->tree[i]);
        }
    }
    free(tree->tree);
    memset(tree, 0, sizeof(Heap));
    return;
}

5、向堆中插入元素

int heap_insert(Heap *heap, const void *data)
{
    void *temp;
    int ipos, ppos;
    //动态扩展数组
    if(( temp = (void **)realloc(heap->tree, (heap->size * sizeof(void *) + 1)) ) == NULL)
        return -1;
    else
    {
        heap->tree = temp;
    }

    //先把要插入的树存入尾部
    heap->tree[heap_size(heap)] = (void *)data;
    ipos = heap_size(heap);
    ppos = heap_parent(ipos);

    //父节点小,则一直和父节点进行交换
    while(ipos > 0 && heap->compare(heap->tree[ppos], heap->tree[ipos]) < 0)
    {
        temp = heap->tree[ppos];
        heap->tree[ppos] = heap->tree[ipos];
        heap->tree[ipos] = temp;

        ipos = ppos;
        ppos = heap_parent(ipos);
    }
    heap->size++;
    return 0;
} 

6、删掉头部,即最大或最小的那个

//去掉头节点,重新排列 
int heap_extract(Heap *heap, void **data)
{
    void *save, *temp;
    int ipos, lpos, rpos, mpos;
    if(heap_size(heap) == 0)
        return -1;
    *data = heap->tree[0];

//先把最后一个元素保存起来,在缩小空间
    save = heap->tree[heap_size(heap) - 1];
    if(heap_size(heap) - 1 > 0)
    {
        if((temp = (void **)realloc(heap->tree, (heap_size(heap) - 1) * sizeof(void *))) == NULL)
            return -1;
        else
        {
            heap->tree = temp;  
        }
        heap->size--;
    } 
    //如果size == 1,重新初始化 
    else
    {
        free(heap->tree);
        heap->tree = NULL;
        heap->size = 0;
        return 0; 
    }

    heap->tree[0] = save;   //最后一个元素移到顶部 
    ipos = 0;
    while(1)
    {
        lpos = heap_left(ipos);
        rpos = heap_right(ipos);
        //左节点标号不能超过最大标号,且左节点大于父节点 ,用mpos保存大的那方 
        if((lpos < heap_size(heap)) && (heap->compare(heap->tree[lpos], heap->tree[ipos]) > 0))
        {
            mpos = lpos;
        }
        else 
        {
            mpos = ipos;
        }
        if((rpos < heap_size(heap)) && heap->compare(heap->tree[rpos], heap->tree[ipos]) > 0)
        {
            mpos = rpos;
        }
        if(mpos == ipos)
        {   
            break;//当前节点大于左右,结束循环 
        }
        else
        {
            temp = heap->tree[mpos];
            heap->tree[mpos] = heap->tree[ipos];
            heap->tree[ipos] = temp;
            ipos = mpos;//这里是标号,向下调整直到调整后的子树父节点大于左右
        }
    } 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值