heap (large top heap)

1. Heap.h

#ifndef __HEAP_H__
#define __HEAP_H__

#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <windows.h>

typedef int HeapDateType;

typedef struct Heap
{
    HeapDateType* _a;
    size_t _size;
    size_t _capacity;
}Heap;

void HeapInit(Heap* hp, HeapDateType* a, size_t n);
void HeapMake(Heap* hp);

void HeapPush(Heap* hp, HeapDateType x);
void HeapPop(Heap* hp);

size_t GetHeapSize(Heap* hp);
size_t HeapEmpty(Heap* hp);
HeapDateType HeapTop(Heap* hp);

void HeapSort(Heap* hp);
void HeapAdjustDown(Heap* hp, int root);
void HeapAdjustUp(Heap* hp, int child);

void HeapPrint(Heap *hp);

#endif __HEAP_H__

2. Heap.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"

//初始化堆
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
    assert(hp);
    hp->_a = (HeapDateType*)malloc(n*sizeof(HeapDateType));
    memcpy(hp->_a, a, n*sizeof(HeapDateType));
    hp->_size = n;
    hp->_capacity = n;
}

//交换
void Swap(HeapDateType *x, HeapDateType *y)
{
    *x ^= *y ^= *x ^= *y;
}

//调整大堆
void HeapAdjust(Heap* hp, int parent, int child)
{
    int flag = 0; //调整标记
    while (child < (int)hp->_size)
    {
        if (child + 1 < (int)hp->_size) //如果右孩子存在,比较左右孩子的数值大小
        {
            if (hp->_a[child] < hp->_a[child + 1])
            {
                child = child + 1; //child取数值大者
            }
        }
        if (hp->_a[child]>hp->_a[parent]) //如果孩子节点数值大于双亲节点数值,进行交换
        {
            flag = 1;
            Swap(&hp->_a[child], &hp->_a[parent]);
        }
        if (flag == 0) //没有调整,说明本身就是大顶堆,循环退出
        {
            break;
        }
        //进行一次调整后,此时可能导致其子树不满足堆的性质,继续向下调整子树直到满足堆的性质
        parent = child;
        child = parent * 2 + 1;
    }
}

//自顶向下调整
void HeapAdjustDown(Heap* hp, int root)
{
    assert(hp);
    HeapAdjust(hp, root, root * 2 + 1);
}

//自底向上调整
void HeapAdjustUp(Heap* hp, int child)
{
    assert(hp);
    assert(child > 0 && child < (int)hp->_size);
    while (child)
    {
        HeapDateType parent = (child - 1) / 2;
        HeapAdjust(hp, parent, child);
        child = parent;
    }
}

//创建堆
void HeapMake(Heap* hp)
{
    int parent = (int)(hp->_size - 2) / 2;
    int child = 0;
    for (; parent >= 0; parent--) //从最后一个非叶子节点开始调整,一直到根节点为止
    {
        child = parent * 2 + 1;
        HeapAdjust(hp, parent, child);
    }
}

//扩容
void CheckCapacity(Heap *hp)
{
    assert(hp);
    if (hp->_size >= hp->_capacity)
    {
        HeapDateType* ptr = (HeapDateType*)realloc(hp->_a, (hp->_capacity + 2)*sizeof(HeapDateType));
        assert(ptr);
        hp->_a = ptr;
        hp->_capacity += 2;
    }
}

//增加
void HeapPush(Heap* hp, HeapDateType x)
{
    assert(hp);
    CheckCapacity(hp);
    hp->_a[hp->_size] = x; //插入到最后一个节点
    hp->_size++;
    HeapAdjustUp(hp, hp->_size - 1); //自底向上调整
}

//删除
void HeapPop(Heap* hp)
{
    assert(hp);
    if (hp->_size == 0)
    {
        return;
    }
    else if (hp->_size == 1)
    {
        hp->_size--;
    }
    else //至少有2个节点
    {
        hp->_a[0] = hp->_a[hp->_size - 1]; //将最后一个节点替换到第一个节点
        hp->_size--;
        HeapAdjustDown(hp, 0); //自顶向下调整
    }
}

//节点个数
size_t GetHeapSize(Heap* hp)
{
    assert(hp);
    return hp->_size;
}

//判空
size_t HeapEmpty(Heap* hp)
{
    assert(hp);
    if (hp->_size)
    {
        return 0; //不为空
    }
    return 1; //为空
}

//获取堆顶元素
HeapDateType HeapTop(Heap* hp)
{
    assert(hp);
    if (hp->_size == 0)
    {
        return -1; //返回-1,代表该堆为空
    }
    return hp->_a[0];
}

//堆排序(建大顶堆->升序)
void HeapSort(Heap* hp)
{
    assert(hp);
    int sz = hp->_size;
    while (hp->_size>1)
    {
        Swap(&hp->_a[0], &hp->_a[hp->_size - 1]); //将第一个节点和最后一个节点的数值交换
        hp->_size--; //最后一个节点已为当前最大值,可不用考虑
        HeapAdjustDown(hp, 0); //自顶向下调整
    }
    hp->_size = sz;
}

//输出
void HeapPrint(Heap *hp)
{
    for (int i = 0; i < (int)hp->_size; i++)
    {
        printf("%d ", hp->_a[i]);
    }
    printf("\n");
}

3. test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "Heap.h"

int main()
{
    Heap hp;
    HeapDateType a[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
    size_t size = sizeof(a) / sizeof(HeapDateType);

    HeapInit(&hp, a, size);
    HeapMake(&hp);
    printf("初始化堆:");
    HeapPrint(&hp);

    if (!HeapEmpty(&hp))
    {
        printf("节点数:%d\n", GetHeapSize(&hp));
    }

    printf("插入100:");
    HeapPush(&hp, 100);
    HeapPrint(&hp);

    printf("删除:");
    HeapPop(&hp);
    HeapPrint(&hp);

    printf("堆顶:%d\n", HeapTop(&hp));

    printf("升序:");
    HeapSort(&hp);
    HeapPrint(&hp);

    system("pause");
    return 0;
}

Program execution result:
write picture description here

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324883602&siteId=291194637