数据结构:堆的实现

首先我简单的介绍一下有关堆的性质:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元 素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: Ki <= K2*i+1 且 Ki<= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2) i = 0,1,2…,则称为小堆(或大堆)。
这里写图片描述

小堆(大堆)中:任一结点的关键码均小于(大于)等于它的左右孩子的关键 码,位于堆顶结点的关键码最小(最大),从根节点到每个结点的路径上数 组元素组成的序列都是递增(递减)的
堆存储在下标为0开始的数组中,因此在堆中给定下标为i的结点时:
如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为 结点(i-1)/2 如果2 * i + 1 <= n - 1,则结点i的左孩子为结点2 * i + 1,否则结 点i无左孩子 如果2 * i + 2 <= n - 1,则结点i的右孩子为结点2 * i + 2,否则结 点i无右孩子
接下来我们开始创建堆(以大堆为列):
首先我们需要一个数组 int a[]={53,17,78,9,45,65,87,23,31}
然后把它抽象成一棵完全二叉树结构,然后进行调整
这里写图片描述

typedef int HeapDateType;
typedef struct Heap
{
    HeapDateType* _a;
    size_t _size;
    size_t _capacity;
}Heap;
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
    int i = 0;
    hp->_capacity = 15;
    hp->_size = 0;
    hp->_a = (HeapDateType*)malloc(sizeof(HeapDateType)*hp->_capacity);
    if (hp->_a == NULL)
        return;
    for (i = 0; i < (int)n; i++)
    {
        hp->_a[i] = a[i];
        hp->_size++;
    }
}

调整的原理:从最后一个非叶子结点开始调整,一直到根节点为止,将每个结点及其子 树调整到满足小堆的性质即可
1:假设该结点的下标为parent
2:找到该结点的左孩子left=parent*2+1
3:如果右孩子right=parent*2+1存在,找到left和right中最大的孩子
4:比较parent是否大于其左右孩子中的大者,如果parent大于较大者,调整结束。否则将parent中元素与较大的孩子交换,此时有可能导致子树不满足堆的性质,继续对其子树进行调整直到满足堆的性质。

void HeapMake(Heap* hp)//创建堆
{
    int i;
    for (i = (hp->_size - 2) / 2; i >= 0; i--)
    {
        HeapAdjustDown(hp,i);//调整函数
    }
}
void HeapAdjustDown(Heap* hp, int root)
{
    int parent = root;
    int child;
    child = 2 * parent + 1;
    while (child<(int)hp->_size)//向下调整,直到不存在孩子
    {
      //选出来较大的孩子
        if (child + 1 <(int) hp->_size&&hp->_a[child + 1] > hp->_a[child])
        {
            child++;
        }
        if (hp->_a[child] > hp->_a[parent])
        {
            HeapDateType tmp = hp->_a[child];//交换
            hp->_a[child] = hp->_a[parent];
            hp->_a[parent] = tmp;
            parent = child;
            child = parent * 2 + 1;
        }
        else
            break;
    }
}

这里写图片描述
堆的插入&删除 :
堆的插入:在已经建成的最大堆的后面插入新元素,插入之后,当树中结点不满足堆的性质时,就需要对堆从下往上进行调整

void HeapPush(Heap* hp, HeapDateType x)
{
    if (hp->_size == hp->_capacity)
    {
        hp->_capacity *= 2;
        hp->_a = (HeapDateType*)realloc(hp->_a, sizeof(HeapDateType)*hp->_capacity);
        assert(hp->_a);
    }
    hp->_a[hp->_size] = x;
    hp->_size++;
    int child = (int)hp->_size - 1;
    HeapAdjustUp(hp, child);
}
void HeapAdjustUp(Heap* hp, int child)
{
    int parent = (child - 1) / 2;
    while (parent >= 0)
    {
        if (hp->_a[child] > hp->_a[parent])
        {
            HeapDateType tmp = hp->_a[child];
            hp->_a[child] = hp->_a[parent];
            hp->_a[parent] = tmp;
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}

堆的删除:删除时每次删除堆顶元素
1:将堆中最后一个元素代替堆顶元素
2:将堆中元素个数减少一个,相当于将堆中最后一个元素删除
3:此时堆结构可能破坏,再向下调整使其满足堆的性质

void HeapPop(Heap* hp)
{
    HeapDateType tmp = hp->_a[0];
    hp->_a[0] = hp->_a[hp->_size - 1];
    hp->_a[hp->_size - 1] = tmp;
    hp->_size--;
    HeapAdjustDown(hp, 0);
}

堆排序:
将堆的根节点取出(一般是与最后一个节点进行交换),将前面size-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。

void HeapSort(Heap* hp)
{
    size_t n = hp->_size;
    while (Heapsize(hp) > 1)
    {
        HeapDateType tmp = hp->_a[0];
        hp->_a[0] = hp->_a[hp->_size - 1];
        hp->_a[hp->_size - 1] = tmp;
        hp->_size--;
        HeapAdjustDown(hp, 0);
    }
    hp->_size = n;
    HeapPrint(hp);
}

代码及函数实现

#include<stdio.h>
#include<windows.h>
#include<malloc.h>
#include<assert.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 HeapEmpty(Heap* hp);
size_t Heapsize(Heap* hp);
HeapDateType HeapTop(Heap* hp);
void HeapSort(Heap* hp);//堆排序
void HeapAdjustDown(Heap* hp, int root);
void HeapAdjustUp(Heap* hp, int child);
#include"Heap.h"
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
    int i = 0;
    hp->_capacity = 15;
    hp->_size = 0;
    hp->_a = (HeapDateType*)malloc(sizeof(HeapDateType)*hp->_capacity);
    if (hp->_a == NULL)
        return;
    for (i = 0; i < (int)n; i++)
    {
        hp->_a[i] = a[i];
        hp->_size++;
    }
}
void HeapPrint(Heap* hp)
{
    int i = 0;
    for (i = 0; i < (int)hp->_size; i++)
    {
        printf("%d ", hp->_a[i]);
    }
    printf("\n");
}
void HeapMake(Heap* hp)
{
    int i;
    for (i = (hp->_size - 2) / 2; i >= 0; i--)
    {
        HeapAdjustDown(hp,i);
    }
}
void HeapAdjustDown(Heap* hp, int root)
{
    int parent = root;
    int child;
    child = 2 * parent + 1;
    while (child<(int)hp->_size)
    {
        if (child + 1 <(int) hp->_size&&hp->_a[child + 1] > hp->_a[child])
        {
            child++;
        }
        if (hp->_a[child] > hp->_a[parent])
        {
            HeapDateType tmp = hp->_a[child];
            hp->_a[child] = hp->_a[parent];
            hp->_a[parent] = tmp;
            parent = child;
            child = parent * 2 + 1;
        }
        else
            break;
    }
}
void HeapPush(Heap* hp, HeapDateType x)
{
    if (hp->_size == hp->_capacity)
    {
        hp->_capacity *= 2;
        hp->_a = (HeapDateType*)realloc(hp->_a, sizeof(HeapDateType)*hp->_capacity);
        assert(hp->_a);
    }
    hp->_a[hp->_size] = x;
    hp->_size++;
    int child = (int)hp->_size - 1;
    HeapAdjustUp(hp, child);
}
void HeapAdjustUp(Heap* hp, int child)
{
    int parent = (child - 1) / 2;
    while (parent >= 0)
    {
        if (hp->_a[child] > hp->_a[parent])
        {
            HeapDateType tmp = hp->_a[child];
            hp->_a[child] = hp->_a[parent];
            hp->_a[parent] = tmp;
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}
void HeapPop(Heap* hp)
{
    HeapDateType tmp = hp->_a[0];
    hp->_a[0] = hp->_a[hp->_size - 1];
    hp->_a[hp->_size - 1] = tmp;
    hp->_size--;
    HeapAdjustDown(hp, 0);
}
size_t HeapEmpty(Heap* hp)
{
    if (hp->_size == 0)
        return 1;
    else
        return 0;
}
size_t Heapsize(Heap* hp)
{
    return hp->_size;
}
HeapDateType HeapTop(Heap* hp)
{
    return hp->_a[hp->_size];
}
void HeapSort(Heap* hp)
{
    size_t n = hp->_size;
    while (Heapsize(hp) > 1)
    {
        HeapDateType tmp = hp->_a[0];
        hp->_a[0] = hp->_a[hp->_size - 1];
        hp->_a[hp->_size - 1] = tmp;
        hp->_size--;
        HeapAdjustDown(hp, 0);
    }
    hp->_size = n;
    HeapPrint(hp);
}
int main()
{
    Heap hp;
    HeapDateType a[]= { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
    size_t n = sizeof(a) / sizeof(a[0]);

    HeapInit(&hp, a, n);
    HeapPrint(&hp);
    HeapMake(&hp);
    HeapPrint(&hp);
    HeapPush(&hp, 100);
    HeapPrint(&hp);
    HeapPop(&hp);
    HeapPrint(&hp);
    HeapSort(&hp);
    system("pause");
    return 0;
}

运行结果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/smx_dd/article/details/80150353