iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C语言数据结构之堆、堆排序的分析及实现
  • 948
分享到

C语言数据结构之堆、堆排序的分析及实现

2024-04-02 19:04:59 948人浏览 八月长安
摘要

目录 1.堆的概念结构及分类1.2堆的分类1.2.1 大堆1.2.2 小堆2. 堆的主要接口3.堆的实现3.1 堆的初始化 Heapinit3.2 堆的销毁 HeapDes

 1.堆的概念结构及分类

以上这段概念描述看起来十分复杂,晦涩难懂。那么堆用通俗语言简单描述如下:

堆是一个完全二叉树的顺序存储。在一个堆中,堆的父节点一定大于等于(或小于等于)子节点。一旦有一部分不满足则不为堆。

堆的性质: 

1、堆中某个节点的值总是不大于或不小于其父节点的值;
2、堆总是一棵完全二叉树

1.2堆的分类

1.2.1 大堆

在一个堆中,父节点一定大于等于子节点的堆称为大堆。又称大根堆。

1.2.2 小堆

在一个堆中,父节点一定小于等于子节点的堆称为小堆。又称小根堆。(下图就是一个小堆)

习题练习:

1.下列关键字序列为堆的是:(A)
A 100,60,70,50,32,65
B 60,70,65,50,32,100
C 65,100,70,32,50,60
D 70,65,100,32,50,60
E 32,50,100,70,65,60
F 50,100,70,65,60,32

分析:选项A分析后为大堆,其他选项多多少少都存在错误。(画图分析如下)

2. 堆的主要接口

在本篇文章中我们主要以小堆为例实现。

现实中我们通常把堆使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

其中堆中包括以下主要功能:

1.堆的初始化   2.堆销毁  3.堆打印  4.堆的插入元素  5.堆删除元素   6.判断堆是否为空  7.求堆中元素的个数  8.求堆顶元素

详细接口如下:

//小堆
//算法逻辑思想是二叉树,物理上操作的是数组中数据
typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;   //数组a
	size_t size;     //下标
	size_t capacity; //容量
}HP;
 
void Swap(HPDataType* pa, HPDataType* pb);//交换函数
void HeapInit(HP* PHP);//堆初始化
void HeapDestory(HP* php);//堆销毁
void HeapPrint(HP* php);//堆打印
 
//插入x以后,仍然要保证堆是(大/小)堆
void HeapPush(HP* php, HPDataType x);
 
//删除堆顶的数据(最大/最小)
void HeapPop(HP* php);
 
bool HeapEmpty(HP* php); //判断是否为空
size_t HeapSize(HP* php);//求元素个数
HPDataType HeapTop(HP* php);//求堆顶元素

3.堆的实现

有了如上的接口,接下来我们实现各个接口。由于我们使用数组来实现堆,大多接口功能和顺序表的实现相同。相同的实现这里不再过多分析。

3.1 堆的初始化 HeapInit

void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = php->capacity = 0;
 
}

3.2 堆的销毁 HeapDestory

void HeapDestory(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->capacity = php->size = 0;
 
}

3.3 堆的打印 HeapPrint

void HeapPrint(HP* php)
{
	assert(php);
	for (size_t i = 0; i < php->size; ++i)
	{
		printf("%d ", php->a[i]);
	}
	printf("\n");
}

3.4 堆的插入元素 HeapPush   *

堆的元素插入是堆的一大重点和难点。接下来我们对该功能进行分析和实现。

功能分析:

1、我们要向堆中插入元素,我们首先要判断数组是否空间已满,如果空间已满就要扩容。扩容后再将新元素插入数组尾部。此过程和顺序表相同。

2、由于插入新元素,我们要对该元素进行分析(此处以如下图小堆举例),分析插入元素是否会破坏堆结构,如果破坏了堆,我们就要对堆进行向上调整。

3、向上调整过程分析(过程步骤如下图):

a. 我们发现出入新元素10之后,10作为28(父节点)的子节点却比28小,这样就破坏了我们的堆结构,这样就不构成小堆。因此我们需要对该结构进行调整。

b.由于堆的物理结构是一个数组,所以我们可以通过数组下标的形式找到我们孩子节点的父节点。不难分析出parent = (child-1)/2.当我们找到父节点时,我们进行大小比较,如果子节点小于父节点,此时就要进行交换元素。再让子节点到父节点的位置,重新计算父节点。

c.持续循环比较,如果child等于0时,说明向上调整结束。因此循环的条件可写为child>0.

注:循环过程中一旦成堆,则跳出循环。

功能实现:

//交换函数
void Swap(HPDataType* pa, HPDataType* pb)
{
	HPDataType tmp = *pa;
	*pa = *pb;
	*pb = tmp;
}
 
 
//向上调整
void AdjustUp(HPDataType* a, size_t child)
{
	size_t 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 HeapPush(HP* php, HPDataType x)
{
	assert(php);
	//考虑是否扩容
	if (php->size == php->capacity)
	{
		size_t newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = realloc(php->a, sizeof(HPDataType) * newCapacity);
		if (tmp == NULL)
		{
			printf("realloc failed\n");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newCapacity;
	}
	php->a[php->size] = x;
	++php->size;
	//需要向上调整
	AdjustUp(php->a, php->size - 1);
}

3.5 堆的删除元素 HeapPop  *

删除堆是删除堆顶的数据 思路:将堆顶的数据跟最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

功能分析:

我们要删除堆是删除堆顶的数据,我们不能直接删除堆顶的数据。如果直接删除堆顶的数据,就会破坏堆结构,并且复原的复杂度较高。在这里我们介绍一种方法不仅解决了删除堆的问题,并且复杂度较低。

1、首先我们要将堆顶的数据跟最后一个数据交换,然后删除数组最后一个数据,再进行向下调整算法。

2、向下调整算法具体步骤(过程步骤如下图):

a.我们将堆顶元素和数组最后一个元素交换后,此时堆顶的元素是数组的最后一个元素,我们要进行向下调整。定义parent为堆顶元素,查找2个子节点中较小的一个节点作为孩子节点。由于堆是数组结构实现,我们可以首先找到左孩子节点child = 2*parent+1。让左孩子和右孩子进行比较,较小的作为child的最后值。

b.如果孩子小于父亲,则交换,并继续往下调整。让parent到child的位置,再重新计算孩子。

c.当孩子大于等于元素总个数时,循环结束。因此循环的条件可以写为child<size.

注:循环过程中一旦成堆,则跳出循环。

功能实现:

void AdjustDown(HPDataType* a, size_t size, size_t root)
{
	size_t parent = root;
	size_t child = parent * 2 + 1;//先拿到左孩子
	while (child < size)
	{
		// 1、选出左右孩子中小的那个
		if (child + 1 < size && a[child + 1] < a[child])
		{
			++child;
		}
 
		// 2、如果孩子小于父亲,则交换,并继续往下调整
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapPop(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);
}

3.6 判断是否为空 HeapEmpty

bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

3.7 求元素个数

size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

3.8 求堆顶元素

HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

 4.堆的应用:堆排序   ***

堆排序即利用堆的思想来进行排序,总共分为两个步骤: 1. 建堆 升序:建大堆 降序:建小堆 2. 利用堆删除思想来进行排序 建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

假设此时我们需要对数组元素进行升序排序,我们就可以使用我们刚刚实现的小堆。

4.1 堆排序实现过程分析

1、首先我们将数组的元素插入到堆中,根据向上调整,此时堆已经是小堆。

2、根据小堆的性质,堆顶的元素一定是该堆中最小的元素,因此我们取到堆顶的元素,再删除堆顶的元素让堆重新生成小堆。依次循环即可解决升序排序(降序排序只需将小堆改为大堆即可)。

4.2 堆排序实现代码

//堆排序
void HeapSort(int* a, int size)
{
	HP hp;
	HeapInit(&hp);
	for (int i = 0; i < size; ++i)
	{
		HeapPush(&hp, a[i]);
	}
	size_t j = 0;
	while (!HeapEmpty(&hp))
	{
		a[j] = HeapTop(&hp);
		j++;
		HeapPop(&hp);
	}
	HeapDestory(&hp);
}
int main()
{
	//	TestHeap();
 
	int a[] = { 4,2,1,3,5,7,9,8,6};
	HeapSort(a,sizeof(a)/sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); ++i)
	{
		printf("%d ", a[i]);
	}
	
	return 0;
}

4.3 堆排序结果演示

5.堆(小堆)的完整代码

2022_03_30 -- 堆/2022_03_30 -- 二叉树 · 李兴宇/数据结构

总结

到此这篇关于C语言数据结构之堆、堆排序的分析及实现的文章就介绍到这了,更多相关C语言堆、堆排序实现内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C语言数据结构之堆、堆排序的分析及实现

本文链接: https://www.lsjlt.com/news/146628.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C语言数据结构之堆、堆排序的分析及实现
    目录 1.堆的概念结构及分类1.2堆的分类1.2.1 大堆1.2.2 小堆2. 堆的主要接口3.堆的实现3.1 堆的初始化 HeapInit3.2 堆的销毁 HeapDes...
    99+
    2022-11-13
  • C语言数据结构堆排序示例分析
    今天小编给大家分享一下C语言数据结构堆排序示例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。TOP.堆排序前言什么是堆排...
    99+
    2023-06-30
  • C语言数据结构中堆排序的分析总结
    目录一、本章重点 二、堆2.1堆的介绍(三点)2.2向上调整2.3向下调整2.4建堆(两种方式)三、堆排序一、本章重点  堆向上调整向下调整堆排序 二、堆 2.1...
    99+
    2022-11-13
  • C语言数据结构之堆排序详解
    目录1.堆的概念及结构2.堆的实现2.1 堆的向下调整算法2.2 堆的向上调整算法2.3 建堆(数组)2.4 堆排序2.5 堆排序的时间复杂度1.堆的概念及结构 如果有一个关键码的集...
    99+
    2022-11-13
  • C语言数据结构二叉树之堆的实现和堆排序详解
    目录一、本章重点二、堆2.1堆的介绍2.2堆的接口实现三、堆排序一、本章重点 堆的介绍堆的接口实现堆排序 二、堆 2.1堆的介绍 一般来说,堆在物理结构上是连续的数组结构,在逻辑结构...
    99+
    2022-11-13
  • C语言数据结构之堆排序的优化算法
    目录1.堆排序优化算法1.1建堆的时间复杂度1.1.1 向下调整建堆:O(N)1.1.2 向上调整建堆:O(N*logN)1.2堆排序的复杂度1.2.1原堆排序的时间复杂度...
    99+
    2022-11-13
  • 【数据结构】堆的实现,堆排序以及TOP-K问题
    目录 1.堆的概念及结构 2.堆的实现 2.1初始化堆 2.2销毁堆 2.3取堆顶元素 2.4返回堆的大小 2.5判断是否为空 2.6打印堆 2.7插入元素 2.8堆的向上调整 2.9弹出元素 2.10堆的向下调整 3. 建堆时间复杂度...
    99+
    2023-09-06
    数据结构 算法
  • C语言怎么实现堆及堆的结构与接口
    本文小编为大家详细介绍“C语言怎么实现堆及堆的结构与接口”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言怎么实现堆及堆的结构与接口”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、堆的结构及实现(重要)1....
    99+
    2023-06-30
  • C语言 深入解读数据结构之堆的实现
    堆的概念与结构 概念:如果有一个关键码的集合K={ k0,k1 ,k2 ,…,kn-1 },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足K i<=K ...
    99+
    2022-11-12
  • 【数据结构】二叉树-堆实现及其堆的应用(堆排序&topK问题)
    文章目录 一、堆的概念及结构二、堆的实现1.结构的定义2.堆的初始化3.堆的插入4.堆的向上调整5.堆的删除6.堆的向下调整7.取出堆顶元素8.返回堆的元素个数9.判断堆是否为空10.打印堆中...
    99+
    2023-09-05
    数据结构 php 开发语言
  • C语言详解如何实现堆及堆的结构与接口
    目录一、堆的结构及实现(重要)1.1 二叉树的顺序结构1.2 堆的概念及结构1.3 堆的实现1.3.1 堆的向下调整算法1.3.2 向下调整算法的时间复杂度1.3.3 堆的创建(向下...
    99+
    2022-11-13
  • C语言植物大战数据结构堆排序图文示例
    目录TOP.堆排序前言一、向下调整堆排序1.向下调整建堆建堆的技巧建堆思路代码2.向下调整排序调整思路排序整体代码3.时间复杂度(难点)向下建堆O(N)向下调整(N*LogN)二、向...
    99+
    2022-11-13
  • C语言数据结构堆的基本操作实现
    目录1.基本函数实现a.代码1(向下调整)b.代码2(向上调整)c.代码3(交换)2.建堆 3.插入数据4. 删除数据5.获取堆顶的数据6.堆的数据个数7.判空8.打印9.销毁10....
    99+
    2022-11-12
  • C语言堆与二叉树的顺序结构与实现
    目录一. 二叉树的顺序结构二. 堆的概念及结构三. 堆的实现四. 堆排序(具有缺陷型)一. 二叉树的顺序结构 普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全...
    99+
    2022-11-13
  • C语言数据结构堆的基本操作实现是怎样的
    本篇文章为大家展示了C语言数据结构堆的基本操作实现是怎样的,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.基本函数实现a.代码1(向下调整)void AdjustDown(DateTyp...
    99+
    2023-06-21
  • Java数据结构之最小堆和最大堆的原理及实现详解
    目录一、前言二、堆的数据结构三、堆的代码实现1. 实现介绍2. 入堆实现3. 出堆实现4. 小堆实现5. 大堆实现一、前言 堆的历史 堆的数据结构有很多种体现形式,包括;2-3堆、B...
    99+
    2022-11-13
  • Java数组实现堆排序的示例分析
    这篇文章主要为大家展示了“Java数组实现堆排序的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java数组实现堆排序的示例分析”这篇文章吧。数组全部入堆,再出堆从后向前插入回数组中,数...
    99+
    2023-05-30
    java
  • C语言数据结构与算法之排序总结(一)
    目录一、前言二、基本概念1.排序2.排序方法的稳定性3.内部和外部排序三、插入类排序1.直接插入排序2.折半插入排序3.希尔排序四、交换类排序1.冒泡排序2.快速排序五、总结比较一、...
    99+
    2022-11-12
  • C语言数据结构与算法之排序总结(二)
    目录一、前言二、选择类排序1.简单选择排序2.树形选择排序3.堆选择排序三、归并排序四、分配类排序1.多关键字排序2.链式基数排序五、总结归纳一、前言 之前的排序总结(一)对插入类和...
    99+
    2022-11-12
  • java实现堆排序以及时间复杂度的分析
    完全二叉树:从上到下,从左到右,每层的节点都是满的,最下边一层所有的节点都是连续集中在最左边。 二叉树的特点就是左子节点是父节点索引值的2倍加一,右子节点是父节点索引值的2倍加二 堆...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作