堆总是一棵完全二叉树
1.创建
我们用一个动态顺序表来实现堆,创建一个结构体封装顺序表
2.初始化
3.销毁
4.插入
这里我们以小堆为例,父亲节点小于儿子节点
以这棵树为例,
在逻辑结构上是一棵二叉树
而在物理结构上是顺序表(即数组)
如果我们分别插入10,20,30
向上调整
具体的流程如图
这里的算法思路是:插入到数组,如果child小于parent,则交换child和parent的值,child的坐标调整到parent,parent则调整到(parent-1)/2,继续进行比较交换,直到child调整到0位置结束,这就是向上调整的思路
向上调整的时间复杂度是O(logN)
5.删除
删除我们规定删除堆顶的值,即删除根节点的值
要求删除根节点之后依然是一个堆
我们的思路是:
- 第一个节点和最后一个节点交换
- 尾删掉最后一个节点
- 然后从根节点开始向下调整
交换之后左右子树依旧是小堆
向下调整
向下调整算法的思路是:
- 找左右child节点
- 左右child节点比较
- 和较小的child节点交换
- 继续向下调整
- 调整到叶子节点就结束
向下调整的时间复杂度是O(logN)
具体的思路是:
找小节点:先找左节点,如果有右节点则比较左右节点,没有就直接是左节点
交换:如果child节点小于parent节点,则交换child和parent的值,然后parent走到child,child走到(parent*2+1)
如果走到叶子节点或者child大于parent节点就跳出循环
6.返回堆顶元素
7.判空
8.返回数据个数
9.访问
总代码
Heap.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <assert.h> typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP; //初始化 void HPInit(HP* php); //销毁 void HPDestroy(HP* php); //交换 void Swap(HPDataType* p1, HPDataType* p2); //向上调整 void AdjustUp(HPDataType* a, int child); //插入(小堆) void HPPush(HP* php, HPDataType x); //向下调整 void AdjustDown(HPDataType* a, int size, int parent); //删除(根节点) void HPPop(HP* php); //返回堆顶数据 int HPTop(HP* php); //判空 bool HPEmpty(HP* php); //返回数据个数 int HPSize(HP* php);
Heap.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "Heap.h"\ //初始化 void HPInit(HP* php) { assert(php); php->a = NULL; php->size = 0; php->capacity = 0; } //销毁 void HPDestroy(HP* php) { assert(php); free(php->a); php->a = NULL; php->size = 0; php->capacity = 0; } //交换 void Swap(HPDataType* p1, HPDataType* p2) { HPDataType 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]) { Swap(&a[child], &a[parent]); child = parent; parent = (child - 1) / 2; } else break; } } //插入(小堆) void HPPush(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++; AdjustUp(php->a, php->size - 1); } //向下调整 void AdjustDown(HPDataType* 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[child], &a[parent]); parent = child; child = parent * 2 + 1; } else break; } } //删除(根节点) void HPPop(HP* php) { assert(php); assert(php->size > 0); Swap(&php->a[0], &php->a[php->size - 1]); php->size--; AdjustDown(php->a, php->size, 0); } //返回堆顶数据 int HPTop(HP* php) { assert(php); assert(php->size > 0); return php->a[0]; } //判空 bool HPEmpty(HP* php) { assert(php); return php->size == 0; } //返回数据个数 int HPSize(HP* php) { assert(php); return php->size; }
test.c
#define _CRT_SECURE_NO_WARNINGS 1 #include "Heap.h" int main() { int a[] = { 1,5,6,8,9,4,2,3 }; int sz = sizeof(a) / sizeof(a[0]); HP hp; HPInit(&hp); for (int i = 0; i < sz; i++) { HPPush(&hp, a[i]); } while (!HPEmpty(&hp)) { printf("%d ", HPTop(&hp)); HPPop(&hp); } printf("\n"); HPDestroy(&hp); return 0; }
















