数据结构---堆的相关操作

什么是堆?

堆满足完全二叉树
小堆(大堆)中:任一结点的关键码均小于(大于)等于它的左右孩子的关键码,位于堆顶结点的关键码最小(最大),从根结点到每个结点的路径上数组元素组成的序列都是递增(递减)的。

我们来看下图:
这里写图片描述
现在,我们对堆进行如下操作:
头文件声明:

//动态扩容,最大尺寸为1024
#define HeapMaxSize 1024

typedef char HeapType;
typedef int(*Compare)(HeapType a,HeapType b);

typedef struct Heap
{
    HeapType data[HeapMaxSize];
    size_t size;
    Compare cmp;
}Heap;

初始化

我们可以选择创建大堆还是小堆,通过结构体成员cmp
如果 a 和 b 满足比较规则,返回1,否则返回0
所谓的比较规则,对于小堆来说,就是 a < b;对于大堆来说,就是a > b。
因此,我们初始化的时候就要决定好是创建大堆还是小堆。

//为小堆建立比较函数
int Less(HeapType a,HeapType b)
{
    return a < b ? 1 : 0;
}

//为大堆建立比较函数
int Greate(HeapType a,HeapType b)
{
    return a > b ? 1 : 0;
}
void HeapInit(Heap* heap,Compare cmp)
{
    if(heap == NULL)
    {
        return;
        //非法输入
    }
    heap->size = 0;
    heap->cmp = cmp;
    return;
}

这里我选择创建了一个大堆。

堆的销毁

void HeapDestroy(Heap* heap)
{
    if(heap == NULL)
    {
        return;
        //非法输入
    }
    heap->size = 0;
    heap->cmp = NULL;
    return;
}

堆的插入

思路:插入一个元素时,可能会改变我们原有的堆的结构,因此需要对其进行调整。先将元素插入到最后,然后对其进行上浮式调整。如果当前插入的元素和它的父节点不满足比较关系,即该节点值大于其父节点(因为我们建的是大堆),就交换两个节点的值,否则,直接退出,停止上浮。
具体代码如下:

void Swap(HeapType* a,HeapType* b)
{
    HeapType tmp = *a;
    *a = *b;
    *b = tmp;
    return;
}
void AdjustUp(Heap* heap,size_t index)
{
    size_t child = index;
    size_t parent = (child-1)/2;
    while(child > 0)
    {
        //如果child和parent不满足比较规则,即child > parent(大堆),就交换child和parent

        if(!heap->cmp(heap->data[parent],heap->data[child]))
        {
            Swap(&heap->data[parent],&heap->data[child]);
        }
        else
        {
            //如果某一个位置下,child和parent已经满足比较规则
            //直接退出,停止上浮
            //因为更上面的节点一定是满足堆的要求的
            break;
        }
        child = parent;
        parent = (child-1)/2;
    }

}
void HeapInsert(Heap* heap,HeapType value)
{
    if(heap == NULL)
    {
        return;//非法输入
    }
    if(heap->size >= HeapMaxSize)
    {
        return;//堆满了
    }
    heap->data[heap->size++] = value;//将元素插入到最后
    AdjustUp(heap,heap->size-1);//将最后一个元素进行上浮式调整
    return;
}

取堆顶元素

直接将堆顶元素通过输出型参数输出

int HeapRoot(Heap* heap,HeapType* value)
{
    if(heap == NULL)
    {
        return 0;//非法输入
    }
    *value = heap->data[0];
    return 1;
}

删除堆顶元素

删除堆顶元素时,堆的结构肯定会发生改变。所以,这里我们的思路是:
先将堆顶元素和最后一个元素进行交换,然后进行尾删,此时原来的堆顶元素已经删除,但此时堆的结构已经破坏,现在的堆顶元素已经不是整个堆中最大的,所以要对其进行下沉式调整。先判断当前节点左右子树谁更大,然后拿最大的和父节点进行交换,直到父节点和其子树满足比较规则,就停止下沉。

具体代码如下:

void AdjustDown(Heap* heap,size_t index)
{
    if(heap == NULL)
    {
        return;//非法输入
    }
    size_t parent = index;
    size_t child = 2 * index + 1;
    while(child < heap->size)
    {
        //如果右子树存在并且比左子树更符合堆的要求
        //大堆,即右子树大于左子树,就让child指向右子树
        if(child+1 < heap->size && heap->cmp(heap->data[child+1],heap->data[child]))
        {
            child = child + 1;
        }
        if(heap->cmp(heap->data[child],heap->data[parent]))
        {
            Swap(&heap->data[child],&heap->data[parent]);
        }
        else
        {
            break;
        }
        parent = child;
        child = parent * 2 + 1;
    }
}
void HeapErase(Heap* heap)
{
    if(heap == NULL)
    {
        return;//非法输入
    }
    if(heap->size == 0)
    {
        return;//空堆
    }
    //交换堆顶元素和最后一个元素
    Swap(&heap->data[0],&heap->data[heap->size-1]);
    //进行尾删;  
    --heap->size;
    //从根结点开始,进行下沉调整
    AdjustDown(heap,0);
    return;
}

堆的创建

我们用数组来创建一个堆,遍历整个数组,然后依次的将数组元素插入到这个堆中即可。插入的时候已经对堆的结构进行了调整。

void HeapCreate(Heap* heap,HeapType array[],size_t size)
{
    if(heap == NULL)
    {
        return;//非法输入
    }
    //遍历array数组,将每个元素依次插入到堆中
    size_t i = 0;
    for( ;i < size;i++ )
    {
        HeapInsert(heap,array[i]);
    }
    return;
}

堆排序

创建堆的时候:
升序 —> 大堆
降序 —> 小堆

//假设我们要升序排序,就要一个大堆
void HeapSort(HeapType array[],size_t size)
{
    //把这个数组构建成一个堆
    Heap heap;
    HeapInit(&heap,Greate);
    HeapCreate(&heap,array,size);
    //循环的删除堆顶元素
    while(heap.size > 0)
    {
        HeapErase(&heap);
    }
    //循环结束后,堆排序就完成
    memcpy(array,heap.data,size * sizeof(HeapType));
    return;
}

堆排序是一种不稳定的排序算法。

猜你喜欢

转载自blog.csdn.net/y6_xiamo/article/details/80412970