119.C++中的heap

119.C++中的heap

1.简介

要想真正了解堆,就需要先了解[二叉树](树和二叉树(Tree&Binary Tree))。

堆是所有树中最具有特点的树,因为它是用数组存储的,并且总是完全二叉树。

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1}把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki<= K2i+1 且 Ki<=K2i+2 ,则称为小堆(或大堆)。

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

最大堆的特点:

1.每个节点最多有两个字节点;

2.根节点的键值是所有堆节点中的最大者,并且每个节点都比自己的孩子节点的值大;

3.除了根节点没有兄弟节点,最后一个左子节点可以没有兄弟节点之外,其它节点必须有兄弟节点。

最小堆就是将最大堆反过来,根节点为最小值。

堆的结构图如下:

2.代码实现

注:以下内容以小堆为例。

(1)堆的定义

typedef struct heap
{
    int* data;
    int size;
    int capacity;
}heap;

(2)堆的交换

void swap(int* a, int* b)
{
    int temp=*a;
    *a=*b;
    *b=temp;
}

(3)检查堆的容量

void checkCapcity(heap* hp)
{
    if (hp->capacity==hp->size)
    {
        int newC;
        if(hp->capacity==0)
        {
            newC=1;
        }
        else
        {
            newC=2*hp->capacity;
        }
        hp->data=(int*)realloc(hp->data, sizeof(int)*newC);
        hp->capacity=newC;
    }
}

(4)初始化

void heapInit(heap* hp)
{
    assert(hp);
    hp->data=NULL;
    hp->capacity=hp->size=0;
}

(5)创建

void heapCreate(heap* hp,int* arr,int n)
{
    assert(hp);
    hp->data=(int*)malloc(sizeof(int)*n);
    memcpy(hp->data,arr,sizeof(int)*n);
    hp->capacity=hp->size=n;
    for(int i=(n-2)/2; i>=0; i--)
    {
        shiftDown(hp->data,hp->size,i);
    }
}

从堆的最后一个非叶子节点开始,依次对每个节点进行shiftDown操作,将它们调整到正确的位置上,以满足堆的性质。这样就可以确保堆中的元素按照特定的顺序排列,以便后续的插入、删除等操作能够正确执行。

(6)销毁

void destory(heap* hp)
{
    assert(hp);
    free(hp->data);
    hp->data=NULL;
    hp->capacity=hp->size=0;
}

(7)插入

void heapPush(heap* hp,int val)
{
    assert(hp);
    checkCapcity(hp);
    hp->data[hp->size++]=val;
    shiftUp(hp->data,hp->size,hp->size-1);
}

执行 shiftUp 操作,将新插入的元素沿着树向上移动,以确保满足堆的性质。

(8)删除

void heapPop(heap* hp)
{
    if(hp->size>0)
    {
        swap(&hp->data[0],&hp->data[hp->size-1]);
        hp->size--;
        shiftDown(hp->data,hp->size,0);
    }
}

这个函数的目的是从堆中删除最大元素,并保持堆的有序性。通过与最后一个元素进行交换来删除最大元素,然后执行 shiftDown 操作,将新的最大元素调整到正确的位置上,以满足堆的性质。

要删除堆中的最大元素,我们需要将堆的第一个元素(最大元素)与最后一个元素进行交换,然后通过执行 shiftDown 操作将新的最大元素调整到正确的位置上。这样做的原因是,删除堆中的元素时,需要保持堆的有序性,即满足最大堆的性质。通过将最大元素与最后一个元素交换位置,可以将最大元素移到堆的最后一个位置,然后执行 shiftDown 操作将新的最大元素调整到正确的位置上,以确保堆的性质仍然满足。这样做可以确保堆在删除元素后仍然是一个有效的最大堆,以便进行后续的插入、删除等操作。

(9)获取堆顶元素

int heapTop(heap* hp)
{
    assert(hp);
    return hp->data[0];
}

(10)判断是不是空堆

int heapEmpty(heap* hp)
{
    if (hp==NULL||hp->size==0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

(11)堆排序

void heapSort(heap* hp)
{
    assert(hp);
    for (int i=(hp->size-2)/2; i>=0; i--)
    {
        shiftDown(hp->data,hp->size,i);
    }
    int end=hp->size-1;
    while(end>0)
    {
        Swap(&hp->data[0],&hp->data[end]);
        shiftDown(hp->data,end,0); 
        end--;
    }
}

(12)打印

void HeapPrint(heap* hp)
{
    assert(hp);
    for(int i=0; i<hp->size; i++)
    {
        cout<<hp->data[i]<<" ";
    }
    cout<<endl;
}

参考:

堆(Heap)

posted @ 2023-07-24 10:51  CodeMagicianT  阅读(137)  评论(0编辑  收藏  举报