【数据结构】堆的实现以及建堆算法和堆排序

avatar
作者
猴君
阅读量:2

【数据结构】堆的实现以及建堆算法和堆排序

🔥个人主页大白的编程日记

🔥专栏数据结构


文章目录

前言

哈喽,各位小伙伴大家好!上期给大家讲了树,二叉树以及堆。今天带着大家实现堆这个数据结构,以及堆排序。话不多说,咱们进入正题!向大厂冲锋!

一.堆的实现

  • 堆的定义
    我们用数组控制堆,在物理上是一个数组。逻辑上想象成堆。然后用size记录堆的节点个数。后面涉及扩容,所以用capacity记录数组空间大小。这里我们实现的是小堆
typedef int HPDataType; typedef struct Heap { 	HPDataType* a; 	int size; 	int capacity; }HP; 
  • 堆的初始化

初始化时我们可以先给堆开好空间,也可以不开。我们不开就先给NULL,然后size和capacity都先给0。

void HPInit(HP* php) { 	assert(php); 	php->a = NULL; 	php->size = php->capacity = 0; }//初始化 
  • 堆的销毁

我们先free销毁数组,在把size和capacity置为0.

void HPDestroy(HP* php) { 	assert(php); 	free(php->a);//销毁数组 	php->a = NULL; 	php->capacity = php->size = 0; }//销毁 

1.1 堆数据的插入

  • 思路分析

想要实现堆的插入,我们需要在数组插入数据后进行向上调整。

  • 堆数据插入
    插入数据前我们需要检查一下是否需要扩容。
    第一次没开空间,我们就给4个数据的空间。
    否则我们就realloc扩容为2倍。
    最后在赋值。然后size++更新节点个数。
    再用向上调整。
void HPPush(HP* php, HPDataType x) { 	assert(php);//断言 	if (php->size == php->capacity)//空间满 	{ 		int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity; 		HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity); 		if (tmp == NULL) 		{ 			perror("realloc fail~"); 			return; 		} 		php->a = tmp; 		php->capacity = newcapacity; 	} 	php->a[php->size++] = x;//插入 	AdjustUp(php->a, php->size);//向上调整 } 
  • 向上调整算法

我们size是数据个数,所以插入的child节点下标为size-1.那我们要找到他的父亲节点就是(child - 1) / 2。
然后判断插入数据和父亲节点的大小关系是否满足堆。
不满足就交换父子节点。然后更新child节点的下标。
满足则停止。或直到child节点到根节点时停止。

void AdjustUp(HPDataType* a, int size) { 	int child = size - 1;//最后的节点 	while (child > 0) 	{ 		int parent = (child - 1) / 2;//父亲节点 		if (a[child] < a[parent])//判断 		{ 			Swap(&a[child], &a[parent]);//交换 			child = parent; 		} 		else 		{ 			break;//调整完成 		} 	} } 

1.2堆数据的删除

  • 思路分析

所以我们需要把最后一个节点和堆的根节点交换后,删除最后一个节点,然后向下调整。

  • 堆数据的删除
    我们先Swap交换根节点和最后一个节点,然后size–删除最后一个节点。再进行向下调整。
void HPPop(HP* php)//删除根节点 { 	assert(php); 	assert(php->size );//判断是否为空 	Swap(&php->a[0], &php->a[php->size-1]);//交换根节点和最后一个节点 	php->size--;//删除堆最后一个数据 	AdjustDown(php->a,php->size,0);//向下调整 } 
  • 向下调整算法
    我们先算parent的左孩子child的下标。
    然后用假设法找出左右孩子最大或最小的那个孩子,注意有可能只有左孩子没有右孩子。所以我们用min+1<size判断是否存在右孩子。然后再将找出的最大或最小孩子与parent节点进行比较。如果不满足堆的大小关系就交换,然后更新parent的下标和新的child的下标。
    满足就break停止循环,或当child<=size说明此时parent为叶子节点停止循环。
void AdjustDown(HPDataType* a, int size,int parent) { 	int child = parent * 2 + 1;//孩子节点 	while (child<size) 	{ 		int min = child;//左右孩子中最小的孩子 		if (min+1<size&&a[min] > a[min + 1])//防止没有右孩子 		{ 			min = child + 1; 		}//假设法 		if (a[parent] > a[min])//判断 		{ 			Swap(&a[parent], &a[min]);//交换 			parent = min; 			child = parent * 2 + 1; 		} 		else 		{ 			break;//调整完毕 		} 	} } 
  • 堆的判空
    直接判断是否size为0
bool HPEmpyt(HP* php) { 	assert(php); 	return php->size == 0;//判空 } 
  • 堆的数据个数

直接返回size即可

int HPSize(HP* php) { 	assert(php); 	return php->size;//返回数据个数 } 
  • 堆顶元素

直接返回下标为0的位置数据即可。

HPDataType HPTop(HP* php) { 	assert(php); 	assert(php->size);//判断是否为空 	return php->a[0];//返回根节点 } 

二.建堆算法和堆排序

现在我们要实现堆排序,那我们需要建堆。
那升序建大堆还是小堆,降序建大堆还是小堆呢?还是都可以呢?
升序建大堆 降序建小堆 为什么呢?

2.1思路分析

那如何建堆呢?
有两种建堆算法。

2.2向上建堆算法

我们堆插入的过程其实就是建堆的过程。

for (int i = 1; i < n; i++) { 	AdjustUp(p,i); } 

2.3向下调整建堆

我们从最后一个父亲节点依次往后向下调整

for (int i = (n - 1 - 1) / 2; i >= 0; i--) { 	AdjustDown(p, n, i); } 

2.4堆排序

实现堆排序,我们升序建大堆,降序建小堆。
两种建堆算法都可以。
然后我们用end表示最后一个堆元素
每次循环交换堆顶元素和最后一个堆元素。
然后堆顶元素向下调整。更新最后一个堆元素即可。

void HeapSort(HPDataType* p, int n) { 	for (int i = 1; i < n; i++)//向上建堆 	{ 		AdjustUp(p,i); 	} 	int end = n - 1;//最后一个堆元素 	while (end > 0)// 	{ 		Swap(&p[0], &p[end]);//交换堆顶元素和最后一个堆元素 		AdjustDown(p,end,0);//向下调整 		end--;//更新最后一个堆元素 	} } 
  • 验证
void HeapSort(HPDataType* p, int n) { 	for (int i = 1; i < n; i++)//向上建堆 	{ 		AdjustUp(p,i); 	} 	int end = n - 1;//最后一个堆元素 	while (end > 0)// 	{ 		Swap(&p[0], &p[end]);//交换堆顶元素和最后一个堆元素 		AdjustDown(p,end,0);//向下调整 		end--;//更新最后一个堆元素 	} } void test2() { 	int a[] = { 9,6,4,7,10,5,3,1,2,8}; 	HeapSort(a, sizeof(a) / sizeof(a[0])); 	for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++) 	{ 		printf("%d ", a[i]); 	} } int main() { 	test2(); 	return 0; } 

后言

这就堆的实现以及建堆算法和堆排序。这都是数据结构的重中之重。
大家一定要多加掌握。今天就分享到这,感谢各位大佬的耐心垂阅!咱们下期见!拜拜~

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!