C语言数据结构之堆排序

青衿之志

履践致远


堆排序(Heapsort) 是指利用 这种数据结构所设计的一种排序算法,它是 选择排序 的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆排降序建小堆

🎥二叉堆

🎥二叉树

🔥期待小伙伴们的支持与关注


目录

堆的创建 

 堆排序的实现

堆排序代码测试 

整体代码实现 

总结✨

稳定性

时间复杂度

空间复杂度

不适用于小数据集

堆的创建 

堆创建的方法

下面我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。

 int a[] = {1,5,3,8,7,6};

我们一般采用 从下往上 建堆的方法,采用 向下调整 算法来建堆:

从倒数的 第一个非叶子节点的子树 开始调整,一直调整到 根节点 的树,就可以调整成堆

建堆的时间复杂度

因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了 简化 使用满二叉树来证明

叶子节点不需要堆化,所以需要堆化的节点从倒数第二层开始

每个节点堆化的过程中,需要 比较交换 的节点个数,跟这个节点的高度 h 成正比

我们只需要将 每个节点的高度求和 ,得出的就是建堆的时间复杂度

因为是 等比 数列,我们可以用  错位相减法 计算时间复杂度
所以建堆的时间复杂度为 O(n)
for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{
	AdjustDown(arr, n, i);
}

这里的  (n - 1 - 1) / 2, n-1 表示下标,其次是套公式(child = parent * 2 + 1)

求出 第一个非叶子节点的子树 并开始向下调整

向下调整算法

void AdjustDown(int* data, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && data[child + 1] > data[child])
		{
			child++;
		}
		if (data[child] > data[parent])
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

我们这里采用了 大根堆 的算法,目的是为了 排升序

为啥排升序需要大根堆呢?

 int a[] = {1,5,3,8,7,6};

我们还是以这个树为栗子

<1>我们可以先交换 堆顶数据堆末数据 ,在进行 向下调整 算法维护堆的性质

<2>因为这样升序待排数据就能先在数据末尾有序,并不断向前推进,最终有序

<3>如果我们采用的是小根堆,我们排的就是降序

结论:排升序建大堆 排降序建小堆

 这里给老铁们动图展示:

 堆排序的实现

void HeapSort(int* arr, int n)
{
	//建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}
	//堆排序
	int len = n - 1;
	while (len)
	{
	//堆顶数据和堆末数据交换
		Swap(&arr[0],& arr[len]);
	//维护树的性质
		AdjustDown(arr, len, 0);
	//剔除已排好的数据
		len--;
	}
}

堆排序代码测试 

int main(void)
{
	int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
	HeapSort(arr, sizeof(arr) / sizeof(int));
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	system("pause");
	return 0;
}


整体代码实现 

#include<stdio.h>
#include<stdlib.h>
void Swap(int* n, int* m)
{
	int tmp = *n;
	*n = *m;
	*m = tmp;
}

void AdjustDown(int* data, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		if (child + 1 < n && data[child + 1] > data[child])
		{
			child++;
		}
		if (data[child] > data[parent])
		{
			Swap(&data[child], &data[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int n)
{
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}
	int len = n - 1;
	while (len)
	{
		Swap(&arr[0],& arr[len]);
		AdjustDown(arr, len, 0);
		len--;
	}
}

int main(void)
{
	int arr[] = { 1,3,5,7,9,2,4,6,8,0 };
	HeapSort(arr, sizeof(arr) / sizeof(int));
	for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	system("pause");
	return 0;
}


总结✨

由于我们建堆的时间复杂度为 O(n)

排序的时间复杂度为 O(nlogn)

所以整体时间复杂度为O(nlogn)

稳定性

同选择排序一样,由于其中交换位置的操作,所以是不稳定的排序算法

时间复杂度

堆排序的最优时间复杂度、平均时间复杂度、最坏时间复杂度均为 O(nlogn)

空间复杂度

是一种原地排序算法,不需要额外的辅助存储空间,只需要原数组上进行元素的交换和调整

不适用于小数据集

堆排序的性能相对较好,但对于小规模的数据集来说,其常数项较大,不如快速排序等算法效率高

✨堆排序的主要优点在于它具有稳定的时间复杂度 O(nlogn),适用于大规模数据集的排序,而且是一种原地排序算法,不需要额外的空间。但它并不适用于小规模数据集,因为其常数项较大。堆排序也不是稳定排序,即相同值的元素在排序后的相对位置可能会改变。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K 个一组翻转链表

题目&#xff1a; struct ListNode{int val;ListNode* next;ListNode(): val(0), next(nullptr) {}ListNode(int _val): val(_val), next(nullptr) {}ListNode(int _val, ListNode* _next): val(_val), next(_next) {} };class Solution { public:ListNode* reverseKGroup(Li…

代码随想录训练营Day21:● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 题目链接 https://leetcode.cn/problems/minimum-absolute-difference-in-bst/description/ 题目描述 思路 遇到在二叉搜索树上求什么最值&#xff0c;求差值之类的&#xff0c;都要思考一下二叉搜索树可是有序的&#xff0c;要利用好这一特点。…

第五十六回 徐宁教使钩镰枪 宋江大破连环马-飞桨图像分类套件PaddleClas初探

宋江等人学会了钩镰枪&#xff0c;大胜呼延灼。呼延灼损失了很多人马&#xff0c;不敢回京&#xff0c;一个人去青州找慕容知府。一天在路上住店&#xff0c;马被桃花山的人偷走了&#xff0c;于是到了青州&#xff0c;带领官兵去打莲花山。 莲花山的周通打不过呼延灼&#xf…

linux设置systemctl启动

linux设置nginx systemctl启动 生成nginx.pid文件 #验证nginx的配置&#xff0c;并生成nginx.pid文件 /usr/local/nginx/sbin/nginx -t #pid文件目录在 /usr/local/nginx/run/nginx.pid 设置systemctl启动nginx #添加之前需要先关闭启动状态的nginx&#xff0c;让nginx是未…

PXI8540高速数据采集卡

XI高速数据采集卡&#xff0c;PXI8540卡是一种基于PXI总线的模块化仪器&#xff0c;可使用PXI系统&#xff0c;在一个机箱内实现一个综合的测试系统&#xff0c;构成实验室、产品质量检测中心等各种领域的数据采集、波形分析和处理系统。也可构成工业生产过程监控系统。它的主要…

EPDM和钉钉集成审批工作—移动端直接处理审批节点,高效协同!

我们发现很多我们工业界的用户&#xff0c;也是有很多是使用钉钉作为日常办公的。于是他们在使用EPDM时&#xff0c;尤其是在日常处理很多审批工作时&#xff0c;希望能和移动端设备和APP一起协同处理。 原文链接&#xff1a;https://www.ict.com.cn/article/20/993.html 钉钉目…

LeetCode刷题---即时食物配送 II

LeetCode题解 解题思路: 1.首先先求出每个用户首次订单表&#xff0c;将其命名为表t &#xff08;select customer_id,min(order_date) as order_datefrom Deliverygroup by customer_id&#xff09;as t2.与原表连接&#xff0c;求出在用户首次订单表中即时订单的数量的总和…

离线强化学习Offline Reinforcement Learning

离线强化学习&#xff08;Offline Reinforcement Learning&#xff0c;简称Offline RL&#xff09;是深度强化学习的一个子领域&#xff0c;它不需要与模拟环境进行交互&#xff0c;而是直接从已有的数据中学习一套策略来完成相关任务。这种方法被认为是强化学习落地的重要技术…

论文阅读:Editing Large Language Models: Problems, Methods, and Opportunities

Editing Large Language Models: Problems, Methods, and Opportunities 论文链接 代码链接 摘要 由于大语言模型&#xff08;LLM&#xff09;中可能存在一些过时的、不适当的和错误的信息&#xff0c;所以有必要纠正模型中的相关信息。如何高效地修改模型中的相关信息而不影…

BUGKU-WEB cookies

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 看源码看F12&#xff1a;看请求链接看提示&#xff1a;cookies欺骗 相关工具 插件&#xff1a;ModHeader或者hackbarbase64解密 解题步骤 看源码 就是rfrgrggggggoaihegfdiofi48ty598whrefeoia…

【算法面试题】-06

智能成绩表 题目描述 小明来到学校当老师&#xff0c;需要将学生按考试总分或单科分数进行排名&#xff0c;你能帮帮他吗&#xff1f; 输入描述 第 1 行输入两个整数&#xff0c;学生人数 n 和科目数量 m。 0 < n < 100 0 < m < 10 第 2 行输入 m 个科目名称&…

java学习(Arrays类和System类)

目录 目录 一.Arrays类 二.System常见方法 三、Biglnteger和BigDecimal&#xff08;高精度&#xff09; 1.Biglnter的常用方法 2.BigDecimal常见方法 3.日期类 1)第一代日期类 2&#xff09;第二代日期类 3)第三代日期类 一.Arrays类 Arrays包含了一系 列静态方法&am…

Nodejs安装

下载下来直接安装 windowr cmd 会自动安装npm命令 node -v npm -v 设置淘宝最新镜像 npm config set registry https://registry.npmmirror.com 查看镜像 npm config get registry 卸载脚手架命令 npm uninstall vue-cli -g 重新安装 npm install vue/cli -g vue --…

力扣98、530、501-java刷题笔记

一、98. 验证二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 1.1题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点…

【嵌入式】嵌入式系统稳定性建设:最后的防线

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟。提供嵌入式方向的学习指导、简历面…

社区医院智慧管理:Java+SpringBoot新实践

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

3/12/24交换排序、插入排序、选择排序、归并排序

目录 交换排序 冒泡排序 快速排序 插入排序 直接插入排序 选择排序 简单选择排序 堆排序 归并排序 各种排序的时间复杂度、空间复杂度、稳定性和复杂度 快排真题2016 选排真题2022 排序算法分为交换类排序、插入类排序、选择类排序、归并类排序。 交换排序 交换排…

如何做到避免客户数据丢失的数据迁移?

数据迁移已成为企业提升竞争力的关键策略。然而&#xff0c;数据迁移过程中的数据丢失问题&#xff0c;一直是企业面临的重大挑战。本文将探讨如何避免数据丢失&#xff0c;分析传统数据迁移的弊端&#xff0c;并介绍镭速数据迁移的优势。 如何避免客户数据丢失的数据迁移 数据…

对日外包:测试方法论

对日开发中的测试方法论 一 根据出力反推入力二 改修PGM的测试成果物三 测试式样书的撰写1 测试式样书的修正2 测试式样书的作成3 提高对日语的重视程度 四 前辈写的测试观点1 测试观点2 测试用语 一 根据出力反推入力 ​ 适用于&#xff0c;改本番数据进行伦理测试&#xff0…

自然语言处理: 第十五章RAG(Retrieval Augmented Generation)

论文地址: [2005.11401] Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (arxiv.org) 代码地址: 可以参考百度文心一言为例子&#xff0c;与本文代码无关 本篇文章主要是介绍Retrieval Augmented Generation下文简称RAG技术的实现原理和代码实现以及大体…