C语言实现堆数据结构和基本 *** 作

C语言实现堆数据结构和基本 *** 作,第1张

总有一种在垃圾堆里刨食的感觉,为了让垃圾堆里多一些有用的东西,我特意写了这个文章。本文章的代码是从别的地方抄来的,如果原作者不希望代码放在这里,请联系帖主删除帖子。

#include 
#include 
#include 
#include 
#include 

typedef int HPDateType;

typedef struct Heap
{
    HPDateType *a;
    int size;
    int capacity;
} HP;

void HeapInit(HP *php, HPDateType *a, int n); // 初始化一个堆
void HeapDestroy(HP *php);                    // 销毁一个堆,释放他的空间
void HeapPush(HP *php, HPDateType x);         // 在堆里面插入一个数,并且让它的结构还是一个堆
void HeapPop(HP *php);                        // 删除堆的顶的数据,并且让它的结构还是一个堆
HPDateType HeapTop(HP *php);                  // 返回堆顶的数据
int HeapSize(HP *php);                        // 返回堆里面数据的个数
bool HeapEmpty(HP *php);                      // 判断堆是否为空
void HeapPrint(HP *php);                      // 输出一个堆
void AdjustUp(HP *st, int child);             // 向上调整算法
void AdjustDown(HP *st, int praent);          // 向下调整算法
void Swap(int *p1, int *p2);                  // 交换值
void HeapSort(HP *php);                       // 堆排序



/*******************************************************************************************************************
    堆(heap)
        什么是堆
    定义
        堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象
        堆的物理结构是一个数组。也可以看成顺序表。元素是每一个结点的值。
        之所以规定完全二叉树, 就是因为最下层的节点都尽量连续靠左,就可以用数组来表示了
    性质
        结构性:用数组表示的完全二叉树
        有序性:任意节点的关键字(权值)是其子树所有节点的最大值(或最小值)
        父节点大于子节点:最大堆(MaxHeap)
        父节点小于子节点:最小堆(MinHeap)
    应用
        1. 优先队列
            “优先队列” (Priority Queue)是特殊的“队列”,从队列中取出元素的顺序是依照元素的优先权(关键字)大小,
            而不是元素进入队列的先后顺序
        2. 堆排序, 用堆来实现的排序算法
    堆的调整算法
        1 向下调整算法
            现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法
            可以把它调整成一个小堆或大堆。但是向下调整算法有一个前提:左右子树必须是一个堆,
            才能调整。所以我们必须从数组的最后一个非叶子节点开始往回对每一个非叶子节点,直到
            根节点使用向下调整算法来调整维护这个堆。
        2 向上调整算法
            我们通过从最后一个叶子节点开始的向上调整算法可以把它调整成一个小堆或大堆。也是通过
            根据此叶子节点找到父亲节点并开始调整,从最后一个叶子节点开始往回直到根节点位置是
            使用向上调整算法来调整维护。
    重要性质
        对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,
        则对于序号为i的结点有:
        1.若i > 0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
        2.若2i + 1 < n,则左孩子序号:2i + 1, 2i + 1 >= n则无左孩子
        3.若2i + 2 < n,则右孩子序号:2i + 2, 2i + 2 >= n则无右孩子
    当得知子节点,反推父节点:  f = (左n - 1) / 2  ,  f = (右n - 2) / 2
***********************************************************************************************************************/




int main(int argc, char **argv)
{
    HP st;
    int a[] = {15, 18, 28, 34, 65, 19, 49, 25, 37, 27};
    int n = sizeof(a) / sizeof(a[0]);

    printf("\ntest HeapInit(), HeapPrint():\n");
    HeapInit(&st, a, n);
    HeapPrint(&st);

    printf("\ntest HeapPush(&st, 8):\n");
    HeapPush(&st, 8);
    HeapPrint(&st);

    printf("\ntest HeapPush(&st, 88):\n");
    HeapPush(&st, 88);
    HeapPrint(&st);

    printf("\ntest HeapPop(&st):\n");
    HeapPop(&st);
    HeapPrint(&st);

    printf("\ntest HeapPop(&st):\n");
    HeapPop(&st);
    HeapPrint(&st);

    printf("\n对堆进行排序:\n");
    HeapSort(&st);
    HeapPrint(&st);


    /* 销毁堆 */
    HeapDestroy(&st);

    if(st.a == NULL)
        printf("\n销毁堆成功\n");

    return 0;
}

// 交换
void Swap(int *p1, int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

// 向上调整算法
void AdjustUp(HP *st, int child)
{
    int parent = (child - 1) / 2;

    while (child > 0)
    {
        if (st->a[child] < st->a[parent])
        {
            Swap(&st->a[child], &st->a[parent]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
            break;
        }
    }
}

// 向下调整算法
void AdjustDown(HP *st, int praent)
{
    int child = praent * 2 + 1;

    while (child < st->size)
    {
        if (child + 1 < st->size && st->a[child + 1] < st->a[child])
        {
            child++;
        }

        if (st->a[child] < st->a[praent])
        {
            Swap(&st->a[child], &st->a[praent]);
            praent = child;
            child = praent * 2 + 1;
        }
        else
        {
            break;
        }
    }
}

void HeapInit(HP *php, HPDateType *a, int n)
{
    if (php == NULL)
        return;

    php->a = (HPDateType *)calloc(1, sizeof(HPDateType) * n);

    if (php->a == NULL)
        exit(EXIT_FAILURE);

    memcpy(php->a, a, sizeof(HPDateType) * n);
    php->capacity = n;
    php->size = n;

    int i;

    //建小堆
    for (i = (php->size - 2) / 2; i >= 0; i--)
        AdjustDown(php, i);
}

void HeapDestroy(HP *php)
{
    if (php == NULL)
        return;

    free(php->a);
    php->a = NULL;
    php->size = 0;
    php->capacity = 0;
}

//在堆里面插入一个数,并且让它的结构还是一个堆
void HeapPush(HP *php, HPDateType x)
{
    if (php == NULL)
        return;

    /* 如果堆的空间满了,就用realloc()重新扩大堆的数组空间的大小 */
    if (php->size == php->capacity)
    {
        HPDateType *temp = (HPDateType *)realloc(php->a, sizeof(HPDateType) * php->capacity * 2);
        if (temp == NULL)
            exit(EXIT_FAILURE);

        php->a = temp;
        php->capacity = php->capacity * 2;
    }

    php->a[php->size] = x;
    php->size++;

    AdjustUp(php, php->size - 1);
}

//删除堆的顶的数据,并且让它的结构还是一个堆
void HeapPop(HP *php)
{
    if (php == NULL)
        return;

    if (HeapEmpty(php))
        return;

    int end = php->size - 1;

    Swap(&php->a[0], &php->a[end]);
    php->size--;

    AdjustDown(php, 0);
}

//返回堆顶的数据
HPDateType HeapTop(HP *php)
{
    if (php == NULL)
        return;

    if (HeapEmpty(php))
        return;

    return php->a[0];
}

//返回堆里面数据的个数
int HeapSize(HP *php)
{
    if (php == NULL)
        return;

    return php->size;
}

//判断堆是否为空
bool HeapEmpty(HP *php)
{
    if (php == NULL)
        return;
    return (php->size == 0);
}

//将堆打印出来
void HeapPrint(HP *php)
{
    int i;
    int m = 1, n = 0;

    printf("\n从上到下输出堆的内容:\n");

    for (i = 0; i < php->size; i++)
    {
        printf("%d ", php->a[i]);
        if (i == n)
        {
            putchar('\n');
            m = m * 2;
            n += m;
        }
    }

    printf("\n\n");
}

void HeapSort(HP *php)
{
    int t = php->size;

    while (php->size != 0)
    {
        HeapPop(php);
    }

    php->size = t;
}

运行效果:

 

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1498193.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-25
下一篇 2022-06-25

发表评论

登录后才能评论

评论列表(0条)

保存