> 文章列表 > c语言 Heap大根堆的实现

c语言 Heap大根堆的实现

c语言 Heap大根堆的实现

堆的简单介绍:

堆是一种特殊的树形数据结构,经常被用来实现优先队列。在实现堆的过程中,可以使用数组实现顺序存储。具体原因如下:

1. 顺序表存储方式简单,易于实现。相比较其他数据结构,如链表等,它不需要频繁地进行内存分配和释放,也不需要复杂的指针操作。

2. 访问数组中的元素是一种很快的操作。由于堆是完全二叉树,因此很容易通过数组下标索引找到任何一个节点的值,其中根节点存储在数组的第一个位置。

3. 堆的操作需要非常高效的访问和修改元素的能力,顺序表天然满足这个需求。在顺序表中插入或删除元素的时间复杂度为O(1),而其他存储方式就不能做到这一点。

4. 顺序表还可以借助计算机缓存特性,充分发挥局部性原理,提高程序运行效率。

总之,使用顺序表来实现堆的主要原因是其简单性和高效性能。


堆的代码注解:

1:使用顺序表创建一个堆:

2:将堆内成员初始化

3:多次用到的数据交换

4:在堆区push一个值,将数据插入尾,再使用Adjustup将尾数据上调

5:Adjustup函数的实现

6:在大根堆中pop数据 

可以先将尾巴的数据与根的数据交换位置,再size--去掉头的元素,最后对根节点进行向下调整

将堆中的根数据删除,顺序表不能直接size--挪动数据,因为挪动数据时会打乱树父子关系

这样,我们就能确保y不但小于等于自己的两个子节点,同时还大于上层的节点。这样不断地交换直至所有数据都插入到原来的二叉堆中,就能确保大根堆的正确性。

并且可以减少因插入元素而造成的数据移动次数,提高效率。

7:ajustdown函数 ,将数据向下调整结构,使得因为pop而将尾数据调整到合适的子位置

 8:判断堆中是否有值,没有值返回true,有值返回false

9:返回根节点的值

10:返回数据的个数


堆的源码展示:

#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>

typedef int HPDataType;

typedef struct heap {
    HPDataType* a;
    int size;
    int capicity;
}HP;

//将堆内成员初始化
void InitHP(HP* php) {
    php->a = (HPDataType*)malloc(sizeof(HPDataType) * 4);
    if (php->a == NULL)
    {
        perror("malloc failed"); 
        return;
    }
    php->size = 0;
    php->capicity = 4;
}

//交换数据

void Swap(HPDataType* p1, HPDataType* p2) {
    HPDataType t = *p1;
    *p1 = *p2;
    *p2 = t;
}

//大根堆排序
void Adjustup(HPDataType* a, int child) {
    int parent = (child - 1) / 2;
    while (a[child] > a[parent] && child != 0)
    {
        //交换数组中的值
        Swap(&a[child], &a[parent]);
        //改变下标
        child = parent;
        parent= (parent - 1) / 2;
    }
}

//插入数据
void PushHP(HP* php, HPDataType child) {
    assert(php);

    //检查内存空间
    if (php->size == php->capicity)
    {
        HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * 2 * php->capicity);
        if (tmp == NULL)
        {
            perror("realloc failed");
        }
        php->a = tmp;
        php->capicity *= 2;
    }
    //插入数据
    php->a[php->size++] = child;
    //大根堆排序
    Adjustup(php->a, php->size - 1);
}

void AdjustDown(HPDataType* a, int size)
{
    int parent = 0;
    //将leftchild当作较大的child
    int child = parent * 2 + 1;
    while (child<size)
    {
        //当leftchild小于rightchild,child++改为右孩子
        if (child + 1 < size && a[child + 1] > a[child])
        {
            ++child;
        }
        //将child与parent下标的值再arr上互换
        Swap(&a[child], &a[parent]);
        parent = child;
        child = parent * 2 + 1;
    } 
}

//判断堆是否为空
bool HeapEmpty(HP* php) {
    assert(php);
    return php->size == 0;
}

//将堆中的根数据删除,顺序表不能直接size--挪动数据,因为挪动数据时会打乱树父子关系
//可以先将尾巴的数据与根的数据交换位置,再size--去掉头的元素,最后对根节点进行向下调整
void PopHP(HP* php) {
    assert(php);
    assert(!HeapEmpty(php));
    //根尾互换
    Swap(&php->a[0], &php->a[php->size - 1]);
    //尾数据的pop
    php->size--;
    //数据向下调整结构
    AdjustDown(php->a, php->size);
}

//返回根节点的值
HPDataType HeapTop(HP* php){
    assert(php);
    return php->a[0];
}

//返回数据的个数
int heapsize(HP* php) {
    assert(php);
    return php->size;
}