追梦之旅【数据结构篇】——详解小白如何使用C语言实现堆数据结构

简介: 堆的概念及结构如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:父结点的值都大于孩子结点的值,则称为大堆;父结点的值都小于孩子结点的值,则称为小堆;大堆也称为大根堆,小堆也叫做小根堆。

微信图片_20230427214238.gif

😎博客昵称:博客小梦

😊最喜欢的座右铭:全神贯注的上吧!!!

😊作者简介:一名热爱C/C++,算法等技术、喜爱运动、热爱K歌、敢于追梦的小博主!

😘博主小留言:哈喽!😄各位CSDN的uu们,我是你的博客好友小梦,希望我的文章可以给您带来一定的帮助,话不多说,文章推上!欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!😘


微信图片_20230427160707.gif


前言🙌



   哈喽各位友友们😊,我今天又学到了很多有趣的知识,现在迫不及待的想和大家分享一下!😘我仅已此文,手把手带领大家追梦之旅【数据结构篇】——详解小白如何使用C语言实现堆数据结构~ 都是精华内容,可不要错过哟!!!😍😍😍


什么是堆?


堆的概念及结构


如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:


父结点的值都大于孩子结点的值,则称为大堆;

父结点的值都小于孩子结点的值,则称为小堆;

大堆也称为大根堆,小堆也叫做小根堆。


堆的性质:


堆中某个节点的值总是不大于或不小于其父节点的值;

堆总是一棵完全二叉树。

微信图片_20230428203915.png微信图片_20230428203920.png


堆的实现


堆向下调整算法


现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整


画图分析:


微信图片_20230428203947.png微信图片_20230428203952.png


堆向下调整算法源代码分享:


向下调整建小堆


//向下调整--建小堆
void AdjustDown(int* a, int size, int parent)
{
  int child = parent * 2 + 1;
  while (child < size)
  {
    if (child + 1 < size && a[child + 1] < a[child])
    {
      child++;
    }
    if (a[child] < a[parent])
    {
      Swap(&(a[parent]), &(a[child]));
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
}


向下调整建大堆


//建大堆
void AdjustDown(int* a, int size, int parent)
{
  int child = parent * 2 + 1;
  while (child < size)
  {
    if (child + 1 < size && a[child + 1] > a[child])
    {
      child++;
    }
    if (a[child] > a[parent])
    {
      Swap(&(a[parent]), &(a[child]));
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
}


堆向上调整算法源代码分享:


画图分析:


微信图片_20230428204103.png微信图片_20230428204107.png


向上调整建小堆


void AdjustUp(HPDataType* a, int child)
{
  assert(a);
  while (child > 0)
  {
    int parent = (child - 1) / 2;
    if (a[child] < a[parent])
    {
      Swap(&(a[child]), &(a[parent]));
      child = parent;
      parent = (child - 1) / 2;
    }
    else
    {
      break;
    }
  }
}


向上调整建大堆


//向上调整建大堆
void AdjustUp(HPDataType* a, int child)
{
  assert(a);
  while (child > 0)
  {
    int parent = (child - 1) / 2;
    if (a[child] > a[parent])
    {
      Swap(&(a[child]), &(a[parent]));
      child = parent;
      parent = (child - 1) / 2;
    }
    else
    {
      break;
    }
  }
}


C语言整体实现堆数据结构源代码分享


堆的插入:


先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。


微信图片_20230428204215.png

void HeapPush(HP* php, HPDataType x)
{
  assert(php);
  //扩容
  if (php->capacity == php->size)
  {
    int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
    HPDataType* tem = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
    if (tem == NULL)
    {
      printf("realloc fail\n");
      exit(-1);
    }
    php->a = tem;
    php->capacity = newcapacity;
  }
  php->a[php->size] = x;
  //向上调整--建小堆
  if(php->size > 0)
    AdjustUp(php->a, php->size);
  php->size++;  
}


堆的删除:


删除堆是删除堆顶的数据,将堆顶的数据和最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。


画图分析:



微信图片_20230428204251.png


void HeapPop(HP* php)
{
  assert(php);
  assert(!HeapEmpty(php));
  Swap(&(php->a[0]), &(php->a[php->size - 1]));
  php->size--;
  AdjustDwon(php->a, php->size,0);
}


头文件(Heap.h)编写:


#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int HPDataType;
typedef struct Heap
{
  HPDataType* a;
  int size;
  int capacity;
}HP;
void Swap(HPDataType* p1, HPDataType* p2);
// O(logN)
void AdjustDwon(HPDataType* a, int size, int parent);
void AdjustUp(HPDataType* a, int child);
void HeapPrint(HP* php);
void HeapInit(HP* php);
void HeapDestroy(HP* php);
void HeapPush(HP* php, HPDataType x);
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
int HeapSize(HP* php);


功能文件(Heap.c)编写:


#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void Swap(HPDataType* p1, HPDataType* p2)
{
  int tem = *p1;
  *p1 = *p2;
  *p2 = tem;
}
// O(logN)
//建小堆
void AdjustDwon(HPDataType* a, int size, int parent)
{
  assert(a);
  int child = parent * 2 + 1;
  while (child < size)
  {
    //选出最小的那个
    if (child + 1 < size && a[child + 1] < a[child])
    {
      child++;
    }
    if (a[child] < a[parent] )
    {
      Swap(&(a[parent]), &(a[child]));
      parent = child;
      child = parent * 2 + 1;
    }
    else
    {
      break;
    }
  }
}
void AdjustUp(HPDataType* a, int child)
{
  assert(a);
  while (child > 0)
  {
    int parent = (child - 1) / 2;
    if (a[child] < a[parent])
    {
      Swap(&(a[child]), &(a[parent]));
      child = parent;
      parent = (child - 1) / 2;
    }
    else
    {
      break;
    }
  }
}
void HeapPrint(HP* php)
{
  assert(php);
  for (int i = 0; i < php->size; i++)
  {
    printf("%d ", php->a[i]);
  }
  printf("\n");
}
void HeapInit(HP* php)
{
  assert(php);
  php->a = NULL;
  php->capacity = php->size = 0;
}
void HeapDestroy(HP* php)
{
  assert(php);
  free(php->a);
  php->a = NULL;
  php->capacity = php->size = 0;
}
void HeapPush(HP* php, HPDataType x)
{
  assert(php);
  //扩容
  if (php->capacity == php->size)
  {
    int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
    HPDataType* tem = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
    if (tem == NULL)
    {
      printf("realloc fail\n");
      exit(-1);
    }
    php->a = tem;
    php->capacity = newcapacity;
  }
  php->a[php->size] = x;
  //向上调整--建小堆
  if(php->size > 0)
    AdjustUp(php->a, php->size);
  php->size++;
}
void HeapPop(HP* php)
{
  assert(php);
  assert(!HeapEmpty(php));
  Swap(&(php->a[0]), &(php->a[php->size - 1]));
  php->size--;
  AdjustDwon(php->a, php->size,0);
}
HPDataType HeapTop(HP* php)
{
  assert(php);
  assert(!HeapEmpty(php));
  return php->a[0];
}
bool HeapEmpty(HP* php)
{
  assert(php);
  return php->size == 0;
}
int HeapSize(HP* php)
{
  assert(php);
  return php->size;
}


测试文件(test.c)编写:


#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void HeapTest1()
{
  HP h;
  HeapInit(&h);
  HeapPush(&h, 15);
  HeapPush(&h, 18);
  HeapPush(&h, 19);
  HeapPush(&h, 25);
  HeapPush(&h, 28);
  HeapPush(&h, 34);
  HeapPush(&h, 65);
  HeapPush(&h, 49);
  HeapPush(&h, 27);
  HeapPush(&h, 37);
  HeapPush(&h, 10);
  printf("%d\n", HeapSize(&h));
  HeapPrint(&h);
  for (int i = 0; i < 8; i++)
  {
    printf("%d ", HeapTop(&h));
    HeapPop(&h);
  }
  printf("\n");
  HeapDestroy(&h);
  printf("%d ", HeapTop(&h));
  HeapPop(&h);
}
int main()
{
  HeapTest1();
  return 0;
}


运行结果测试截图:


微信图片_20230428204425.png


总结撒花💞


   本篇文章旨在分享详解小白如何使用C语言实现堆数据结构。希望大家通过阅读此文有所收获

   😘如果我写的有什么不好之处,请在文章下方给出你宝贵的意见😊。如果觉得我写的好的话请点个赞赞和关注哦~😘😘😘

相关文章
|
3天前
|
存储 算法 C语言
通义灵码在考研C语言和数据结构中的应用实践 1-5
通义灵码在考研C语言和数据结构中的应用实践,体验通义灵码的强大思路。《趣学C语言和数据结构100例》精选了五个经典问题及其解决方案,包括求最大公约数和最小公倍数、统计字符类型、求特殊数列和、计算阶乘和双阶乘、以及求斐波那契数列的前20项和。通过这些实例,帮助读者掌握C语言的基本语法和常用算法,提升编程能力。
|
3天前
|
存储 算法 C语言
【趣学C语言和数据结构100例】
《趣学C语言和数据结构100例》精选5个编程问题,涵盖求最大公约数与最小公倍数、字符统计、特殊序列求和及阶乘计算等,通过实例讲解C语言基础与算法思维,适合初学者实践学习。
|
10天前
|
存储 JavaScript 前端开发
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
为什么基础数据类型存放在栈中,而引用数据类型存放在堆中?
37 1
|
13天前
|
存储 C语言
探索C语言数据结构:利用顺序表完成通讯录的实现
本文介绍了如何使用C语言中的顺序表数据结构实现一个简单的通讯录,包括初始化、添加、删除、查找和保存联系人信息的操作,以及自定义结构体用于存储联系人详细信息。
17 2
|
1月前
|
存储 Java
【数据结构】优先级队列(堆)从实现到应用详解
本文介绍了优先级队列的概念及其底层数据结构——堆。优先级队列根据元素的优先级而非插入顺序进行出队操作。JDK1.8中的`PriorityQueue`使用堆实现,堆分为大根堆和小根堆。大根堆中每个节点的值都不小于其子节点的值,小根堆则相反。文章详细讲解了如何通过数组模拟实现堆,并提供了创建、插入、删除以及获取堆顶元素的具体步骤。此外,还介绍了堆排序及解决Top K问题的应用,并展示了Java中`PriorityQueue`的基本用法和注意事项。
40 5
【数据结构】优先级队列(堆)从实现到应用详解
|
18天前
|
存储 算法 调度
数据结构--二叉树的顺序实现(堆实现)
数据结构--二叉树的顺序实现(堆实现)
|
19天前
|
存储 算法 分布式数据库
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
【初阶数据结构】理解堆的特性与应用:深入探索完全二叉树的独特魅力
|
11天前
|
存储 算法
探索数据结构:分支的世界之二叉树与堆
探索数据结构:分支的世界之二叉树与堆
|
13天前
|
存储 算法 Java
【用Java学习数据结构系列】用堆实现优先级队列
【用Java学习数据结构系列】用堆实现优先级队列
26 0
|
15天前
|
存储 算法
【数据结构】二叉树——顺序结构——堆及其实现
【数据结构】二叉树——顺序结构——堆及其实现