【C语言】堆排序

news2025/1/12 21:36:13

堆排序即利用堆的思想来进行排序,总共分为两个步骤:


1. 建堆
升序:建大堆
降序:建小堆

原因分析:

若升序建小堆时间复杂度是O(N^2)

升序建大堆,时间复杂度O(N*logN)

所以升序建大堆,降序建小堆


2. 利用堆删除思想来进行排序


建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。

代码实现

#include<stdio.h>

//交换函数
void Swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}
//向下调整算法
void AdjustDown(int* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
void HeapSort(int* a, int n)
{
	//建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}
int main()
{
	int a[] = { 0,4,3,6,7,8,1 };
	HeapSort(a, sizeof(a) / sizeof(int));
	return 0;
}

运行结果

若是建小堆则只需要把向下调整中的>改成<,修改后如下

if (child + 1 < n && a[child + 1] < a[child])
{
	child++;
}
if (a[child] < a[parent])
{
	Swap(&a[child], &a[parent]);
	parent = child;
	child = child * 2 + 1;
}

运行结果

当然我们也可以先写一个堆的数据结构再进行堆排序,但是这显然不如上面的快速且节省空间

自主实现数据结构堆再进行堆排序

代码实现

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>


typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;
//初始化
void HPArrayInit(HP* hp, HPDataType* a, int n);
//销毁
void HPDestroy(HP* hp);
// 堆的插入
void HPPush(HP* hp, HPDataType x);
// 堆的删除
void HPPop(HP* hp);
// 取堆顶的数据
HPDataType HPTop(HP* hp);
// 堆的数据个数
int HPSize(HP* hp);
// 堆的判空
int HPEmpty(HP* hp);
//向上调整算法
void Adjustup(HPDataType* a, int child);
//向下调整算法
void AdjustDown(HPDataType* a, int n, int parent);


void HPArrayInit(HP* hp, HPDataType* a, int n)
{
	assert(hp);
	hp->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (hp->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	memcpy(hp->a, a, n * sizeof(HPDataType));
	hp->size = hp->capacity = n;
	//向上调整,建堆时间复杂度O(N*logN)
	for (int i = 1; i < hp->size; i++)
	{
		Adjustup(hp->a, i);
	}
	//向下调整,建堆时间复杂度O(N)
	for (int i = (hp->size - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(hp->a, hp->size, i);
	}
}
//销毁
void HPDestroy(HP* hp)
{
	assert(hp);
	hp->size = hp->capacity = 0;
	free(hp->a);
	hp->a = NULL;
}
//交换函数
void Swap(HPDataType* px, HPDataType* py)
{
	HPDataType tmp;
	tmp = *px;
	*px = *py;
	*py = tmp;
}
//向上调整算法
void Adjustup(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;
			parent = (parent - 1) / 2;//找原本父亲的父亲下标
		}
		else
		{
			break;
		}
	}
}
// 堆的插入
void HPPush(HP* hp, HPDataType x)
{
	assert(hp);
	//扩容
	if (hp->size == hp->capacity)
	{
		int newcapacity = hp->capacity == 0 ? 4 : 2 * hp->capacity;
		HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		hp->a = tmp;
		hp->capacity = newcapacity;
	}
	hp->a[hp->size++] = x;
	Adjustup(hp->a, hp->size - 1);
}
//向下调整算法
void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] < a[child])
		{
			child++;
		}
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
// 堆的删除
void HPPop(HP* hp)
{
	assert(hp);
	assert(hp->size > 0);
	Swap(&hp->a[0], &hp->a[hp->size - 1]);

	hp->size--;
	AdjustDown(hp->a, hp->size, 0);
}
// 取堆顶的数据
HPDataType HPTop(HP* hp)
{
	assert(hp);
	return hp->a[0];
}
// 堆的数据个数
int HPSize(HP* hp)
{
	assert(hp);
	return hp->size;
}
// 堆的判空
int HPEmpty(HP* hp)
{
	assert(hp);
	return hp->size == 0;
}
void HeapSort(int* a, int n)
{
	HP hp;
	HPArrayInit(&hp, a, n);
	int i = 0;
	while (!HPEmpty(&hp))
	{
		a[i++] = HPTop(&hp);//将堆顶数据放入数组中
		HPPop(&hp);//再已放入数组中的堆顶数据删除
	}
	HPDestroy(&hp);
}
int main()
{
	int a[] = { 60,70,65,50,32,100 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

运行结果

欢迎各位大佬一起学习交流~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1968669.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

记一次对HTB:Carpediem的渗透测试

信息收集 端口扫描 通过nmap对靶机端口进行探测&#xff0c;发现存在22和80端口。 访问web页面。发现是一个静态页面&#xff0c;没有可利用的部分。 目录扫描 子域枚举 通过对域名进行fuzz子域名&#xff0c;发现存在portal一级域名。 将它加入/etc/hosts&#xff0c;访问之…

vue3+gsap实现圆形路径动画

同学们可以私信我加入学习群&#xff01; 正文开始 前言一、引入并使用gsap二、详解gsap.to的各参数三、路径svg四、其他路径文字路径动画总结 前言 我开发的桌面端软件最近增加了在线更新功能&#xff0c;其中更新动画部分是由gsap实现的&#xff0c;整体实现思路已经在elect…

用Python打造精彩动画与视频,3.2 基本的剪辑和合并操作

3.2 基本的剪辑和合并操作 在这一节中&#xff0c;我们将学习如何使用 MoviePy 库对视频进行基本的剪辑和合并操作。MoviePy 是一个用于视频编辑的 Python 库&#xff0c;可以轻松地实现视频的剪辑、合并、添加音频等操作。 准备工作 首先&#xff0c;确保你已经安装了 Movi…

花几千上万学习Java,真没必要!(三十九)

1、BufferedReader的使用&#xff1a; 测试代码&#xff1a; package test.com; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class FileReadToList { pu…

OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI基本开发步骤(三)

引言 前面文章OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI&#xff08;一&#xff09; 和 OpenHarmony 入门——初识JS/ArkTS 侧的“JNI” NAPI 常见的函数详解&#xff08;二&#xff09;介绍了NAPI的基础理论知识&#xff0c;今天重点介绍下如何去开发一个自己的NAP…

maven插件2(spring-api-auth-valid-plugin)

https://maven.apache.org/guides/mini/guide-configuring-plugins.htmlhttps://maven.apache.org/plugin-testing/maven-plugin-testing-harness/getting-started/index.html plugin-desc 业务功能 所有的endpoint,必须带有指定的安全校验标签,如spring-security的PreAuthori…

RabbitMQ 集群安装

在 linux 下手动安装 RabbitMQ 集群。 准备 安装之前的准备工作。 准备内容说明其他3 台服务器centos、redhat 等ErlangRabbitMQ 运行需要的基础环境socatRabbitMQ 运行需要的基础环境logrotateRabbitMQ 运行需要的基础环境这个服务器一般自带了 下面的安装示例中使用的版本…

一键测量仪,能否彻底解决燃气灶配件缺陷问题?

燃气灶配件是指用于燃气灶的附件或零部件&#xff0c;用于安装、维护或改进燃气灶的功能和性能。这些配件通常包括各种零部件、附件和替换件&#xff0c;以确保燃气灶的正常运行和安全使用。燃气灶的火焰头是产生火焰的部件&#xff0c;通常根据不同的燃气类型和火力需求选择合…

python-求四位数(赛氪OJ)

[题目描述] 3025 这个数具有一种独特的性质&#xff1a;将它平分为二段&#xff0c;即 30 和 25&#xff0c;使之相加后求平方&#xff0c;即 (3025)^2&#xff0c;恰好等于 3025 本身。请求出具有这样性质的全部四位数。输入格式&#xff1a; 此题没有输入。输出格式&#xff…

详解并掌握AXI4总线协议(一)、AXI4-FULL接口介绍

系列文章目录 文章目录 系列文章目录一、AXI介绍二、AXI4、AXI-Lite、AXI4-Stream区别三、AXI4读写架构3.1 通道定义3.2 读突发时序3.3 写突发时序 四、AXI4-FULL 总线信号介绍4.1全局信号4.2 写地址通道信号4.3 写数据通道信号4.4 写响应通道信号4.5 读地址通道信号4.6 读数据…

Animate软件基础:在时间轴中添加或插入帧

FlashASer&#xff1a;AdobeAnimate2021软件零基础入门教程https://zhuanlan.zhihu.com/p/633230084 FlashASer&#xff1a;实用的各种Adobe Animate软件教程https://zhuanlan.zhihu.com/p/675680471 FlashASer&#xff1a;Animate教程及作品源文件https://zhuanlan.zhihu.co…

抖音爆火的“拆盲盒”直播,是如何将昂贵的废品卖给消费者的?

抖音直播间掀起了一股“拆盲盒”热潮。 最初&#xff0c;这股热潮主要集中在拆卡直播间。一盒10包起卖的卡牌&#xff0c;价格在100~200不等。拆卡主播拿起剪刀行云流水的开盒、拆卡、过牌&#xff0c;一晚上能轻松跑出数万元的营业额。数据显示&#xff0c;头部卡牌公司卡游仅…

Redis+Unity 数据库搭建

游戏中需要存放排行榜等数据&#xff0c;而且是实时存放&#xff0c;所以就涉及到数据库的问题。这里找服务器大神了解到可以用Redis来做存储&#xff0c;免费的效率极高。 Redis的搭建参考上文的文章&#xff0c;同时也感谢这位网友。 搭建Redis 并测试数据 搭建Redis 1.下…

玩转云服务:Google Cloud谷歌云永久免费云服务器「白嫖」 指南

前几天&#xff0c;和大家分享了&#xff1a; 玩转云服务&#xff1a;Oracle Cloud甲骨文永久免费云服务器注册及配置指南 相信很多同学都卡在了这一步&#xff1a; 可用性域 AD-1 中配置 VM.Standard.E2.1.Micro 的容量不足。请在其他可用性域中创建实例&#xff0c;或稍后…

Kafka设计与原理详解

RocketMQ 是一款开源的分布式消息系统&#xff0c;基于高可用分布式集群技术&#xff0c;提供低延时的、高可靠的消息发布与订阅服务。同时&#xff0c;广泛应用于多个领域&#xff0c;包括异步通信解耦、企业解决方案、金融支付、电信、电子商务、快递物流、广告营销、社交、即…

使用kettle开源工具进行跨库数据同步

数据库同步可以用&#xff1a; 1、Navicat 2、Kettle 3、自己写代码 调用码神工具跨库数据同步 -连接 4、其它 实现 这里使用Kettle来同步&#xff0c;主要是开源的&#xff0c;通过配置就可以实现了 Kettle的图形化界面&#xff08;Spoon&#xff09;安装参考方法 ht…

Maven实战.依赖(依赖范围、传递性依赖、依赖调解、可选依赖等)

文章目录 依赖的配置依赖范围传递性依赖传递性依赖和依赖范围依赖调解可选依赖最佳实践排除依赖归类依赖优化依赖 依赖的配置 依赖会有基本的groupId、artifactld 和 version等元素组成。其实一个依赖声明可以包含如下的一些元素&#xff1a; <project> ...<depende…

单例模式及其思想

本文包括以下几点↓ 结论&#xff1a;设计模式不是简单地将一个固定的代码框架套用到项目中&#xff0c;而是一种严谨的编程思想&#xff0c;旨在提供解决特定问题的经验和指导。 单例模式&#xff08;Singleton Pattern&#xff09; 意图 旨在确保类只有一个实例&#xff…