C语言---数据结构---堆

要想了解堆结构,首先要知道什么是堆、堆是用来做什么的。

那么什么是堆呢?

如果有一个关键码的集合K,K中包含n个数据,将这些元素按照完全二叉树的顺序存储方式存储在一个一维数组中,并满足第i个数据小于等于第2*i+1个数据且第i个数据小于等于第2*i+2个数据(i为数组下标),则称其为小堆(大堆:第i个数据大于等于第2*i+1个数据且第i个数据大于等于第2*i+2个数据)。将根节点最大的堆叫做大根堆或最大堆,将根节点最小的堆叫做小根堆或最小堆。

堆的性质:

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

2、堆总是一颗完全二叉树。

如何实现堆:

既然堆是由数组来实现的那么我们来提供一组数据,默认这组数据是一颗完全二叉树。

cpp 复制代码
int array[] = {27,15,19,18,28,34,65,49,25,37};

接下来我们利用这组数据使用向下调整算法来创建堆。

复制代码
void HeapSort(int* arr, int sz)
{
	//首先使用前几个数据进行建堆
    //对于一个包含 sz 个元素的数组,其最后一个非叶子节点的下标计算方式为 (sz - 2) / 2
    //(叶子节点本身就是一个完整的堆,所以不需要再进行调整)
	for (int i = (sz - 2) / 2; i >= 0; i--)
	{
		//向下调整
		AdjustDown(arr, i, sz);
	}

	//使堆顶数据和最后的数据进行交换
	//并继续进行向下调整算法
	int end = sz - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, 0, end);
		end--;
	}
}

void AdjustDown(int* arr, int parent, int sz)
{
	//左子树
	int child = parent * 2 + 1;
	while (child < sz)
	{
		//先判断左子树和右子树的大小
		//建小堆取大值,建大堆取小值
		if (child + 1 < sz && arr[child] > arr[child + 1])
		{
			child++;
		}
		//判断子树和父节点谁大谁小
		if (arr[child] < arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}

上面的代码是以建大根堆的形式展现的,如果需要建小根堆则调整判定条件即可

调整1:将左右孩子节点中的选择改为让较大值和父节点比较

调整2:如果孩子节点大于父节点再进行交换

建堆分为两种方法,一种是向上调整算法,一种是向下调整算法,向上调整一般用于数据的插入,向下调整一般用与数据的删除!

上面的是向下调整算法,下面是向上调整算法

复制代码
void AdjustUp(int* arr, int child)
{
	int parent = (child - 1) / 2;
	//不需要等于,child只要走到根节点的位置,根节点没有父节点不需要交换
	while (child > 0)
	{
		//建大堆,>
		//建小堆,<
		if (arr[child] < arr[parent])
		{
			Swap(&arr[parent], &arr[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}
堆的作用

1.可以用于排序算法中的一项

2.可以解决一些用于处理大量数据中的前几项(最大的几项或者最小的几项)比如TOP-K问题

TOP-K问题

即获取一段数据中的前K个最大值或者最小值

首先来创建一段数据

复制代码
void CreateNDate()
{
	// 造数据
	int n = 10000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}
	for (size_t i = 0; i < n; ++i)
	{
		int x = rand() % 1000000;
		fprintf(fin, "%d\n", x);
	}
	fclose(fin);
}

然后使用前K个数据建堆

复制代码
//使用前K个数据造堆
for (int i = (k - 1 - 1) / 2; i >= 0; i--)
{
	//找前K个最大的数据使用小堆
	AdjestDown(arr, 0, n - 1);
}

接下来遍历数据中的每一个值,将大于堆顶的数据进堆并进行排序

复制代码
	//定义一个变量用于接收文件中的值
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		//将读取到的数据跟堆顶的数据进行比较
		//读取到的数据大于堆顶的数据,进行交换
		if (x > arr[0])
		{
			arr[0] = x;
			AdjestDown(arr, 0, n);
		}
	}

此时我们就得到了所有数据中最大的前K个

相关推荐
山峰哥5 分钟前
沉浸式翻译插件深度评测:打破语言壁垒的黑科技利器
数据结构·科技·算法·编辑器·办公
Bona Sun1 小时前
单片机手搓掌上游戏机(十六)—pico运行fc模拟器之程序修改烧录
c语言·c++·单片机·游戏机
小邓   ༽2 小时前
50道C++编程练习题及解答-C编程例题
c语言·汇编·c++·编程练习·c语言练习题
报错小能手2 小时前
数据结构 定长顺序表
数据结构·c++
再卷也是菜3 小时前
C++篇(21)图
数据结构·c++·算法
Bona Sun3 小时前
单片机手搓掌上游戏机(十三)—pico运行fc模拟器之硬件准备
c语言·c++·单片机·游戏机
Bona Sun3 小时前
单片机手搓掌上游戏机(十八)—pico运行fc模拟器之更大屏幕
c语言·c++·单片机·游戏机
没书读了4 小时前
数据结构-考前记忆清单
数据结构
小龙报4 小时前
【算法通关指南:数据结构和算法篇 】队列相关算法题:3.海港
数据结构·c++·算法·贪心算法·创业创新·学习方法·visual studio
Yue丶越4 小时前
【C语言】自定义类型:结构体
c语言·开发语言