数据结构-堆

一、堆的简介

 
堆通常是一个可以被看做一棵完全二叉树的数组对象

堆总是满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
 

二、堆的结构

 
堆是一个完全二叉树的数组对象,所以堆的结构体中包含了数组指针,数组大小和数组容量。

typedef int HPDataType;
typedef struct Heap
{
    HPDataType* _a; // 数组指针
    HPDataType _size; // 数组大小
    HPDataType _capacity; // 数组容量
}Heap;

 

三、堆的函数接口

void Swap(HPDataType* a, HPDataType* b);// 交换

void SmallAdjustDown(HPDataType* a, size_t n, size_t parent);// 小堆向下调整
void BigAdjustDown(HPDataType* a, size_t n, size_t parent);// 大堆向下调整

void HeapInit(Heap* hp, HPDataType* a, int n);// 初始化
void HeapDestory(Heap* hp);// 销毁

void SmallAdjustup(Heap* hp, HPDataType x);// 小堆向上调整
void BigAdjustup(Heap* hp, HPDataType x);// 大堆向上调整

void HeapPush(Heap* hp, HPDataType x);// 插入
void HeapPop(Heap* hp); // 删除

HPDataType HeapTop(Heap* hp); // 取堆顶元素
int HeapSize(Heap* hp); // 堆大小
int HeapEmpty(Heap* hp); // 堆是否为空

void HeapSort(HPDataType* a, size_t n);// 堆排序 
void HeapPrint(Heap* hp);// 打印堆

 

四、函数接口实现

 
4.1  Swap交换函数
 
Swap函数按照传地址的方式,直接使用第三方交换指针指向的内容。

void Swap(HPDataType* a, HPDataType* b)// 交换
{
    HPDataType c;
    c = *a;
    *a = *b;
    *b = c;
}

4.2  小堆向下调整
 
我们把已经创建好的数组从根节点开始向下调整成一个小堆,因为要调成一个小堆,所以前提是该二叉树里面,左右子树必须是一个堆,才能调整。小堆就是父结点小于孩子结点,建立循环遍历,调整孩子结点和父结点位置即可。

void SmallAdjustDown(HPDataType* a, size_t n, size_t parent)// 小堆向下调整
{
    size_t child = parent * 2 + 1;
    while (child < n)
    {
        // 选出小的那个孩子
        if (child + 1 < n && a[child + 1] < a[child])
            ++child;
        // 如果孩子小于父亲,则交换
        if (a[child] < a[parent])
        {
            Swap(&(a[child]),&(a[parent]));
            parent = child;
            child = parent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

4.3  大堆向上调整
 
和小堆向下调整类似,大堆是父结点大于孩子结点。

void BigAdjustDown(HPDataType* a, size_t n, size_t parent)// 大堆向下调整
{
    size_t child = parent * 2 + 1;
    while (child < n)
    {
        // 选出大的那个孩子
        if (child + 1 < n && a[child + 1] > a[child])
            ++child;
        // 孩子大于父亲,则交换
        if (a[child] > a[parent])
        {
            Swap(&(a[child]), &(a[parent]));
            parent = child;
            child = parent * 2 + 1;
        }
        else    break;
    }
}

4.4  初始化
 
在初始化的时候,我们把堆结构体的成员赋初值,并且构建出一个小(大)堆。

void HeapInit(Heap* hp, HPDataType* a, int n)// 初始化
{
    hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n);
    memcpy(hp->_a, a, sizeof(HPDataType)*n);
    hp->_capacity = n;
    hp->_size = n;
    
    //构建小堆
    for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    {
        SmallAdjustDown(hp->_a, hp->_size, i);
    }
    // 构建大堆
    /*for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    {
        BigAdjustDown(hp->_a, hp->_size, i);
    }*/
}

4.5  销毁
 
释放掉堆所占的数组空间,把堆结构体中的成员置空置0。

void HeapDestory(Heap* hp)// 销毁
{
    assert(hp);
    if (hp->_a)
    {
        free(hp->_a);
        hp->_a = NULL;
        hp->_capacity = 0;
        hp->_size = 0;
    }
}

4.6  小堆向上调整
 
小堆满足父结点小于孩子结点,把不满足要求的结点位置进行调整。

void SmallAdjustup(Heap* hp, HPDataType child)// 小堆向上调整
{
    HPDataType parent = (child - 1) / 2;
    while (child != 0)
    {
        if (hp->_a[child] < hp->_a[parent])
        {
            Swap(&(hp->_a[child]), &(hp->_a[parent]));
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

4.7  大堆向上调整
 
大堆满足父结点大于孩子结点,把不满足要求的结点位置进行调整。

void BigAdjustup(Heap* hp, HPDataType child)// 大堆向上调整
{
    HPDataType parent = (child - 1) / 2;
    while (child != 0)
    {
        if (hp->_a[child] > hp->_a[parent])
        {
            Swap(&(hp->_a[child]), &(hp->_a[parent]));
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

4.8  插入
 
在堆尾插入一个元素,再调用向上调整算法。

void HeapPush(Heap* hp, HPDataType x)// 插入
{
    hp->_a[hp->_size] = x;
    SmallAdjustup(hp, hp->_size);
    //BigAdjustup(hp, hp->_size);
    hp->_size++;
}

4.9  删除
 
删除堆是删除堆顶元素,把堆顶元素和最后一个元素一换,再删除数组最后一个元素,进行向下调整算法。

void HeapPop(Heap* hp) // 删除
{
    Swap(&(hp->_a[0]), &(hp->_a[hp->_size - 1]));
    hp->_size--;
    SmallAdjustDown(hp, hp->_size,hp->_a[0]);
}

4.10  取堆顶元素
 
直接利用数组下标返回。

HPDataType HeapTop(Heap* hp) // 取堆顶元素
{
    return hp->_a[0];
}

4.11  堆大小
 
堆的大小就是数组大小。

int HeapSize(Heap* hp) // 堆大小
{
    return hp->_size;
}

4.12  堆是否为空
 
如果数组大小是0,则堆为空。

int HeapEmpty(Heap* hp) // 堆是否为空
{
   if (hp->_size == 0)
   {
       return 1;
   }
   else return 0;
}

4.13  堆排序
 
升序建大堆,降序建小堆。

void HeapSort(int* a, size_t n)// 堆排序 
{
    for (int i = (n - 2) / 2; i >= 0; --i)
    {
        SmallAdjustDown(a, n, i);
    }
    int end = n - 1;
    while (end > 0)
    {
        Swap(&a[end], &a[0]);
        SmallAdjustDown(a, end, 0);
        --end;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值