每日回顾:简单用C搓个数组堆

heap.h------标准库包含、函数声明

heap.c------函数定义

main.c------测试

堆的逻辑结构是一颗完全二叉树:

heap.h

heap.h中应包含如下定义和功能:

cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<stdlib.h>

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}Heap;

// 堆初始化
void HeapInit(Heap* php);
// 堆的销毁
void HeapDestory(Heap* hp);

//向上调整
void AdjustUp(HPDataType* a, int child);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);

//向下调整
void AdjustDown(HPDataType* a, int n, int parent);
// 堆的删除(删除堆顶元素)
void HeapPop(Heap* hp);

// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
bool HeapEmpty(Heap* hp);

heap.c

逐个在 heap.c 中实现上述功能,同时保证代码的健壮性

heap.c 中包含 heap.h

1、堆初始化

cpp 复制代码
// 堆初始化
void HeapInit(Heap* php) {
	assert(php);
	php->a = NULL;
	php->capacity = 0;
	php->size = 0;
}

2、堆的销毁

cpp 复制代码
// 堆的销毁
void HeapDestory(Heap* hp) {
	assert(hp);
	free(hp->a);
}

3、向上调整

cpp 复制代码
//交换元素
void Swap(HPDataType* p1, HPDataType* p2) {
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//向上调整
void AdjustUp(HPDataType* a, int child) {
	int parent = (child - 1) / 2;
	//只要 child 有效,都会进入循环判断
	while (child > 0) {
		//建立大堆
		if (a[child] > a[parent]) {
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else {	//已满足堆的条件
			break;
		}
	}
}

4、堆的插入

cpp 复制代码
// 堆的插入
void HeapPush(Heap* hp, HPDataType x) {
	assert(hp);
	//检查容量,如果已满,扩容
	if (hp->size == hp->capacity) {
		int newCapacity = hp->capacity == 0 ? 4 : hp->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newCapacity);
		if (tmp == NULL) {
			perror("realloc failed");
			return;
		}
		hp->a = tmp;
		hp->capacity = newCapacity;
	}

	hp->a[hp->size++] = x;
	//尾插新数据后,向上调整
	//传入数组和孩子下标
	AdjustUp(hp->a, hp->size - 1);
}

5、向下调整

cpp 复制代码
//向下调整
void AdjustDown(HPDataType* a, int n, int parent) {
	int child = parent * 2 + 1;	//左孩子
	//调整时,parent 要与 左右孩子中大的那个交换--
	//--以保证满足大堆条件

	while (child < n) {
		//选出左右孩子中较大者
		if ((child + 1) < n && a[child] < a[child + 1]) {
			child++;
		}

		if (a[parent] < a[child]) {
			Swap(&a[parent], &a[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else {	//已满足大堆条件
			break;
		}
	}
}

6、堆的删除

cpp 复制代码
// 堆的删除(删除堆顶元素)
void HeapPop(Heap* hp) {
	//交换堆顶和堆底元素,删除堆底元素,向下调整
	assert(hp);
	assert(!HeapEmpty(hp));	//堆不能为空

	Swap(&hp->a[0], &hp->a[hp->size - 1]);
	hp->size--;
	AdjustDown(hp->a, hp->size, 0);
}

7、取堆顶元素

cpp 复制代码
// 取堆顶的数据
HPDataType HeapTop(Heap* hp) {
	assert(hp);
	assert(!HeapEmpty(hp));	//堆不能为空
	return hp->a[0];
}

8、堆的数据个数

cpp 复制代码
// 堆的数据个数
int HeapSize(Heap* hp) {
	assert(hp);
	return hp->size;
}

9、判断堆空

cpp 复制代码
// 堆的判空
bool HeapEmpty(Heap* hp) {
	assert(hp);
	return hp->size == 0;
}

main.c

cpp 复制代码
#include"heap.h"

void Test1() {
	Heap hp;
	HeapInit(&hp);

	HeapPush(&hp, 2);
	HeapPush(&hp, 1);
	HeapPush(&hp, 3);
	HeapPush(&hp, 6);
	HeapPush(&hp, 5);
	HeapPush(&hp, 9);
	HeapPush(&hp, 2);

	for (int i = 0; i < hp.size; i++) {
		printf("%d ", hp.a[i]);
	}
	printf("\n");

	HeapPop(&hp);
	for (int i = 0; i < hp.size; i++) {
		printf("%d ", hp.a[i]);
	}

	HeapDestory(&hp);
}

int main() {
	Test1();
	return 0;
}

将存储的数据拆成完全二叉树后,仍然是大堆,没有问题

相关推荐
axxy20001 小时前
leetcode之hot100---240搜索二维矩阵II(C++)
数据结构·算法
Uu_05kkq2 小时前
【C语言1】C语言常见概念(总结复习篇)——库函数、ASCII码、转义字符
c语言·数据结构·算法
1nullptr4 小时前
三次翻转实现数组元素的旋转
数据结构
TT哇4 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表
嵌入式科普5 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
A懿轩A5 小时前
C/C++ 数据结构与算法【栈和队列】 栈+队列详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·栈和队列
1 9 J6 小时前
数据结构 C/C++(实验五:图)
c语言·数据结构·c++·学习·算法
汝即来归6 小时前
选择排序和冒泡排序;MySQL架构
数据结构·算法·排序算法
仍然探索未知中7 小时前
C语言经典100例
c语言
爱吃西瓜的小菜鸡7 小时前
【C语言】矩阵乘法
c语言·学习·算法