堆的介绍与堆的实现和调整

2023-09-17 20:09:37

个人主页:Lei宝啊

愿所有美好如期而遇


目录

​​堆的介绍:

关于堆的实现及相关的其他问题:

堆的初始化:

堆的销毁:

插入建堆:

堆向上调整:

交换两个节点的值:

堆向下调整:

删除根节点:

求堆顶数据:

打印堆的每一个节点的值:

堆排序:

堆的节点数量:

判断堆是否为空:

创建一个多数据文件:

TopK问题(综合):

向上/向下调整建堆哪个时间复杂度更优秀?


​​堆的介绍:

首先,堆是不完全二叉树。

不完全二叉树:除了最后一层外,其他层每一层都是满的,最后一层节点从左到右排。

再者,堆分为大堆和小堆

大堆:父母节点的值大于等于孩子节点

小堆:父母节点的值小于等于孩子节点

关于堆的实现及相关的其他问题:

我们在主函数中将定义一个Heap hp;

typedef int Heaptype;
typedef struct Heap
{
	Heaptype* data;
	int size;
	int capacity;
}Heap;

//堆的初始化
void HeapInit(Heap* php);
//堆的销毁
void HeapDestroy(Heap* php);
//插入建堆
void HeapPush(Heap* php, Heaptype num);
//堆向上调整
void Ajustup(Heaptype* a, int child);
//交换两个节点的值
void Swap(Heaptype* p1, Heaptype* p2);
//堆向下调整
void AjustDown(Heaptype* a, int n, int parent);
//删除根节点
void HeapPop(Heap* php);
//求得堆顶数据
Heaptype HeapTop(Heap* php);
//打印堆的每一个节点的值
void HeapPrint(Heaptype* arr, int size);
//堆排序
void HeapSort(Heaptype* arr, int size);
//堆的节点数量
void HeapSize(Heap* php);
//判读堆是否为空
void HeapEmpty(Heap* php);
//创建一个多数据文件
void CreateNDate();
//TopK问题
void PrintTopK(int k);

堆的初始化:

void HeapInit(Heap* php)
{
	assert(php);

	php->data = NULL;
	php->size = 0;
	php->capacity = 0;
}

堆的销毁:

void HeapDestroy(Heap* php)
{
	assert(php);

	free(php->data);
	php->data = NULL;
	php->size = 0;
	php->capacity = 0;
}

插入建堆:

void HeapPush(Heap* php, Heaptype num)
{
	assert(php);
	
	if (php->size == php->capacity)
	{
		int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		Heaptype* temp = (Heaptype*)realloc(php->data, sizeof(Heaptype) * newcapacity);
		if (temp == NULL)
		{
			perror("realloc fail");
			printf("\n%s", __LINE__);
		}

		php->data = temp;
		php->capacity = newcapacity;
	}

	php->data[php->size++] = num;
    
    //插入后当即向上调整,以保证还是个堆
	Ajustup(php->data, php->size - 1);
}

堆向上调整:

//堆向上调整,调整一轮,建堆就循环插入去建
void Ajustup(Heaptype* a, int child)
{

	int parent = (child - 1) / 2;

	//当child == 0 的时候,parent也为0
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
		
}

交换两个节点的值:


void Swap(Heaptype* p1, Heaptype* p2)
{

	Heaptype temp = *p1;
	*p1 = *p2;
	*p2 = temp;

}

堆向下调整:

//堆向下调整
void AjustDown(Heaptype* a, int n, int parent)
{
	
	//从根节点开始
	int child = parent * 2 + 1;

	while (child < n)
	{
		//找出最小孩子
		if (child + 1 < n && a[child] > a[child + 1])
		{
			child++;
		}
		else
		{
			if (a[parent] > a[child])
			{
				Swap(&a[child], &a[parent]);
				parent = child;
				child = parent * 2 + 1;
			}	
			else
			{
				break;
			}
		}
	}

}

删除根节点:

void HeapPop(Heap* php)
{
	assert(php);
	assert(php->size > 0);

	Swap(&php->data[0], &php->data[php->size - 1]);
	AjustDown(php->data, php->size - 1, 0);

	php->size--;
}

求堆顶数据:

Heaptype HeapTop(Heap* php)
{
	assert(php);

	return php->data[0];
}

打印堆的每一个节点的值:

void HeapPrint(Heaptype* arr, int size)
{
	assert(arr);

	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
}

堆排序:

void HeapSort(Heaptype* arr, int size)
{
	assert(arr);

	//向上调整建堆(小堆)
	/*int num = size;
	for (int i = 0; i < num; i++)
	{
		Ajustup(arr, i);
	}*/

	//向下调整建堆
	int last = (size - 1) / 2;
	for (int i = last; i >= 0; i--)
	{
		AjustDown(arr, size, i);
	}

	//排序
	int end = size - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AjustDown(arr, end, 0);
		end--;
	}
}

堆的节点数量:

void HeapSize(Heap* php)
{
	assert(php);

	return php->size;
}

判断堆是否为空:

void HeapEmpty(Heap* php)
{
	assert(php);

	return php->size == 0;
}

创建一个多数据文件:

void CreateNDate()
{
	int n = 10000;
	srand((unsigned int)time(NULL));

	const char* file = "heap.txt";
	FILE* pf = fopen(file, "w");
	{
		if (pf == NULL)
		{
			perror("fopen fail");
			return;
		}
	}

	for (int i = 0; i < n; i++)
	{
		int num = rand() % 1000000;
		fprintf(pf, "%d\n", num);
	}

	fclose(pf);

}

TopK问题(综合):

void PrintTopK(int k)
{
	Heaptype* arr = (Heaptype*)malloc(sizeof(Heaptype) * k);	
	if (arr == NULL)
	{
		perror("malloc fail");
		return;
	}
	
	FILE* pf = fopen("heap.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}

	for (int i = 0; i < k; i++)
	{
		fscanf(pf, "%d", &arr[i]);
	}
    
    //调整为小堆
	int n = (k - 1 - 1) / 2;
	for (int i = n; i >= 0; i--)
	{
		AjustDown(arr, k, i);
	}

    //由于我们建1的是大小为k的堆,堆顶的数值最小,当新的数据大于堆
    //顶时,进堆,而堆顶的数据被替换,之后堆向下调整
	int a = 0;
	while (fscanf(pf, "%d", &a) != EOF)
	{
		if (a > arr[0])
		{
			arr[0] = a;
			AjustDown(arr, k, 0);
		}
	}
    //此时堆里的数据是最大的k个数	
		
	for (int i = 0; i < k; i++)
	{
		printf("%d ", arr[i]);
	}

	fclose(pf);
	free(arr);
}

向上/向下调整建堆哪个时间复杂度更优秀?

答案是堆向下调整,时间复杂度为O(N),堆向上调整时间复杂度为O(N*logN)。


更多推荐

【力扣每日一题】2023.9.21 收集树中金币

目录题目:示例:分析:代码:题目:示例:分析:题目给我们一棵树,不过这棵树不是普通的树,而是无向无根树。给我们一个二维数组表示节点之间的连接关系,以及一个一维数组表示每个节点是否有金币。我们可以从任何一个节点出发,并且可以收集距离两格的节点的金币,每次可以移动到相邻的节点。问我们要收集完所有的金币并且最终要回到起点,最

Python爬虫:aiohttp的介绍和基本使用

aiohttp是一个用于编写异步网络应用程序的Python库,它建立在Python3.5+的asyncio框架之上。它允许你创建高性能的异步HTTP客户端和服务器,以处理并发请求和响应。下面是关于aiohttp的介绍和基本使用方法:安装aiohttp你可以使用pip来安装aiohttp:pipinstallaiohtt

python魔术方法_对象_继承_复写_变量注解_函数注解_多态(04)

文章目录python魔术方法_对象_继承_复写_变量注解_函数注解_多态(04)1对象的魔术方法1.1魔术方法实例:2对象的封装2.1私有变量:开头__(2个下划线)定义2.2案例私有变量访问:3继承3.1类继承语法:3.2类继承案例3.3多继承3.3.1多继承语法3.3.2多继承属性(pass使用)4复写4.1对父类

如何使用ArcGIS Pro提取河网水系

DEM数据除了可以看三维地图和生成等高线之外,还可以用于水文分析,这里给大家介绍一下如何使用ArcGISPro通过水文分析提取河网水系,希望能对你有所帮助。数据来源本教程所使用的数据是从水经微图中下载的DEM数据,除了DEM数据,常见的GIS数据都可以从水经微图中下载,你可以通过关注公号“水经注GIS”,然后在后台回复

1.8python基础语法——数据类型转换

1)转换数据类型的作用用户输入的数据是字符串类型,可以用类型转换将字符串类型转换为相应的数据类型。2)转换数据类型的函数函数说明int(x[,base])将x转换为一个整数float(x)将x转换为一个浮点数complex(real[,imag])创建一个复数,real为实部,imag为虚部str(x)将对象x转换为字

软件设计原则扩展

一、引言经典的软件设计7大原则开闭原则(OpenClosePrinciple,OCP)依赖倒置原则(DependenceInversionPrinciple,DIP)单一职责原则(SimpleResponsibilityPrinciple,SRP)接口隔离原则(InterfaceSegregationPrinciple

从零开始学习 Java:简单易懂的入门指南之不可变集合、方法引用(二十六)

不可变集合、方法引用1.不可变集合1.1什么是不可变集合1.2使用场景1.3不可变集合分类1.4不可变的list集合1.5不可变的Set集合1.6不可变的Map集合1.6.1:键值对个数小于等于101.6.2:键值对个数大于102.方法引用2.1体验方法引用2.2方法引用符2.3引用类方法2.4引用对象的实例方法2.5

【数据结构】TOP-K问题/使用堆解决

💐🌸🌷🍀🌹🌻🌺🍁🍃🍂🌿🍄🍝🍛🍤📃个人主页:阿然成长日记👈点击可跳转📆个人专栏:🔹数据结构与算法🔹C语言进阶🚩不能则学,不知则问,耻于问人,决无长进🍭🍯🍎🍏🍊🍋🍒🍇🍉🍓🍑🍈🍌🍐🍍文章目录TOP-K问题一、题目描述二、思路:三、代码实现1.随机产生一万

【每日一题】852. 山脉数组的峰顶索引

852.山脉数组的峰顶索引-力扣(LeetCode)符合下列属性的数组arr称为山脉数组:arr.length>=3存在i(0<i<arr.length-1)使得:arr[0]<arr[1]<...arr[i-1]<arr[i]arr[i]>arr[i+1]>...>arr[arr.length-1]给你由整数组成的山

数据结构——二叉树提升

二叉树题型练习前言一、节点个数以及高度等二、二叉树OJ题二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历单值二叉树二叉树最大深度检查两颗树是否相同.翻转二叉树对称二叉树另一颗树的子树总结前言现在我们开始一轮新的自我提升吧!二叉树的题目当然也更有难度!没有什么是生来就会的,尤其是代码这一方面更是讲究熟能生巧,现在的我们学

全能电子地图下载器3.0-下载离线地图瓦片

前言vue项目要部署到局域网内,不使用在线地图,而是离线地图,寻求了很多的解决方案,最终决定使用离线地图瓦片+leaflet.js实现效果!正文首先需要下载正版的软件,目前我实用的是V3.0版本的,可能和之前的有部分差异化,这个也属于正常。一、下载1.有CSDN会员下载渠道:https://download.csdn.

热文推荐