堆(C语言实现)
创始人
2024-03-03 12:12:44
0

文章目录:

  • 1.堆的概念
  • 2.堆的性质
  • 3.堆的结构
  • 4.接口实现
    • 4.1初始化堆
    • 4.2销毁堆
    • 4.3打印堆内元素
    • 4.4向上调整
    • 4.5向堆中插入数据
    • 4.6向下调整
    • 4.7删除堆顶元素
    • 4.8查看堆顶元素
    • 4.9统计堆内数据个数
    • 4.10判断堆是否为空
    • 4.11堆的构建

1.堆的概念

如果有一个关键码的集合,把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,孩子节点都不大于父节点的称为小堆,孩子节点都不大于其父节点的称为大堆

图示:

由此可以看出:任何数组都可以看做完全二叉树,但不一定是堆

2.堆的性质

1.堆中某个节点的值总是不大于或不小于其父节点的值
2.堆总是一棵完全二叉树
3.孩子节点和父亲节点下标的关系:

  • parent = (child - 1) / 2
  • leftchild = parent * 2 + 1
  • rightchild = parent * 2 + 2

3.堆的结构

堆总是一棵完全二叉树,堆是用数组来存储的

typedef int HPDataType;//数据类型
typedef struct Heap
{HPDataType* a;//数组int size;//数据个数int capacity;//容量
}HP;

4.接口实现

4.1初始化堆

将数组指针指向NULL,将数据个数和容量置零方便后面统计和判断容量,这里断言php是防止人为不小心传入了空指针

//初始化堆
void HeapInit(HP* php)
{assert(php);php->a = NULL;// 指空php->size = php->capacity = 0;// 置零
}

4.2销毁堆

释放掉数组,并将数组指针指空,将数据个数和容量置零即可

//销毁堆
void HeapDestroy(HP* php)
{assert(php);free(php->a);//释放php->a = NULL;//指空php->size = php->capacity = 0;//置零
}

4.3打印堆内元素

遍历数组将其内的元素打印出来即可

//打印堆内元素
void HeapPrint(HP* php)
{assert(php);	//遍历打印for(int i = 0; i < php->size; ++i){printf("%d ", php->a[i]);}printf("\n");
}

4.4向上调整

将孩子节点的数据和其父结点的数据进行比较,若孩子节点的数据大于(小于)父节点的数据就交换并继续向上调整,直到根结点(数组中下标为0的元素)位置就停止,这里对父子节点的比较是根据堆是大堆还是小堆来决定的

//交换函数
void Swap(HPDataType* p1, HPDataType* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}//向上调整
void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0){//孩子大于(小于)父亲,就交换并继续向上调整,反之则调整结束//if (a[child] > a[parent])if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

4.5向堆中插入数据

首先创建一个新节点,并判断数组是否需要扩容,然后直接向数组尾部插入一个数据,将该数据向上调整(保证结构继续是个堆)即可

//向堆中插入数据
void HeapPush(HP* php, HPDataType x)
{assert(php);//判断扩容if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);if (tmp == NULL)//判断防止扩容失败{perror("realloc fail");exit(-1);}php->a = tmp;php->capacity = newcapacity;}//将新的数据插入数组尾部php->a[php->size] = x;php->size++;//数据个数+1AdjustUp(php->a, php->size - 1);//从尾节点开始向上调整
}

4.6向下调整

将孩子节点的数据和其父结点的数据进行比较,若孩子节点的数据大于(小于)父节点的数据就交换并继续向小调整,直到最后一个节点(数组中的最后一个的元素)就停止,这里对父子节点的比较是根据堆是大堆还是小堆来决定的

//向下调整
void AdjustDown(HPDataType* a, int n, int parent)
{int child = parent * 2 + 1;//默认是左孩子while (child < n){//确认child指向大的(小的)那个孩子//if (a[child + 1] > a[child] && child + 1 < n)if (a[child + 1] < a[child] && child + 1 < n){++child;//换成右孩子}//孩子大于(小于)父亲,就交换并继续向下调整,反之则调整结束//if (a[child] > a[parent])if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

4.7删除堆顶元素

将堆顶元素和堆尾数据元素交换并删除堆尾(此时堆尾数据也就是堆顶数据),再从根节点开始向下调整(保证它继续是个堆)即可,这里需要断言堆为空的情况,为空不能删

//删除堆顶元素
void HeapPop(HP* php)
{assert(php);//断言堆为空assert(php->size > 0);//交换堆顶元素和堆尾元素Swap(&php->a[0], &php->a[php->size - 1]);php->size--;//数据个数-1AdjustDown(php->a, php->size, 0);//从根节点开始向下调整
}

4.8查看堆顶元素

数组首元素就是堆顶元素,直接将其返回即可,这里需要断言堆为空的情况,为空无堆顶元素

//查看堆顶元素
HPDataType HeapTop(HP* php)
{assert(php);//断言堆为空assert(php->size > 0);//返回数组首元素(堆顶元素)return php->a[0];
}

4.9统计堆内数据个数

结构体中的size就是有效数据的个数,直接将其返回即可

//统计堆内数据个数
int HeapSize(HP* php)
{assert(php);//返回有效数据个数return php->size;
}

4.10判断堆是否为空

如果堆内的有效数据个数为0,则堆为空,直接返回其布尔值即可

//判断堆是否为空
bool HeapEmpty(HP* php)
{assert(php);//有效数据个数为0则堆为空return php->size == 0;
}

4.11堆的构建

我们可以人为传入一个数组来建堆,首先需要开辟一个与传入的数组大小相同的空间,用来将数组中的内容复制到该空间中,然后从最后一个元素的父节点开始((size-1-1)/2)依次向前可以遍历到每颗子树的父节点,并对每颗子树向下调整

//堆的构建
void HeapCreate(HP* php, HPDataType* a, int n)
{assert(php);php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (php->a == NULL){perror("malloc fail");exit(-1);}//将数组复制到开辟的空间中memcpy(php->a, a, sizeof(HPDataType) * n);php->size = php->capacity = n;//建堆算法//从最后一个元素的父节点开始依次向前可以遍历到每颗子树的父节点for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(php->a, n, i);}
}

图解:


堆的实现到这里就介绍结束了,期待大佬们的三连!你们的支持是我最大的动力!
文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正。

相关内容

热门资讯

*ST惠程[002168]关于... 本版导读 2025-12-23 2025-12-23 2025-12-23 2025...
一次性信用修复政策实施,哪些人... 为支持信用受损但积极还款的个人高效便捷重塑信用,助力经济持续回升向好,12月22日,中国人民银行对外...
美国民主党籍州总检察长就资金问... 来源:金十数据 12月23日,据华尔街日报报道,由多名民主党籍州总检察长组成的联盟周一提起诉讼,试图...
日本多名教职人员因性暴力或性犯... 据日本文部科学省22日公布的数据,日本2024财年(2024年4月至2025年3月)共有281名公立...
山西一网友发布疑似看守所监控视... 山西一网友发布疑似看守所监控视频,房间内有多人身着统一蓝色制服,还有一人戴着脚镣;警方称此类视频禁止...
《郑州市中医药发展促进条例》全... 【大河财立方消息】郑州市人民代表大会常务委员会公告,《郑州市中医药发展促进条例》已经郑州市第十六届人...
【行业观察】 政策护航 公募R... 戴丹苗(国信证券经济研究所分析师) REITs(不动产投资信托基金)在中国经历了从私募到公募,从债性...
关于《河南省烟草专卖管理条例(... 主任、各位副主任、秘书长、各位委员: 2025年7月,省十四届人大常委会第十八次会议对《河南省烟草专...
日本文部科学省:281名教职人... 中新网12月23日电 据日本广播协会(NHK)等日媒报道,当地时间22日,日本文部科学省表示,日本2...
涉及网约车、电梯……“法规体检... 12月22日,全国人大常委会法工委关于2025年备案审查工作情况的报告提请全国人大常委会会议审议。在...