深入理解堆排序:建堆、排序与优化

引言

在计算机科学中,堆排序是一种高效的排序算法,利用堆的数据结构特性进行排序。本文将深入探讨堆排序的原理、实现过程,并介绍一种优化方法,以帮助读者更好地理解和运用这一经典算法

 

目录

  1. 堆排序简介

    • 1.1 什么是堆排序?

    • 1.2 堆排序的应用场景

  2. 建堆过程

    • 2.1 堆的基本概念回顾

    • 2.2 第一种建堆方法:向上调整

    • 2.3 代码实例:建立小堆的问题

  3. 排序过程

    • 3.1 选择建大堆的原因

    • 3.2 代码优化:建大堆方式

    • 3.3 排序实现详解

  4. 性能分析与优化

    • 4.1 时间复杂度分析

    • 4.2 为何选择建大堆?

    • 4.3 可能的性能优化方案

     5.总结与展望

  • 5.1 堆排序的优缺点总结

  • 5.2 未来的优化方向

 

1. 堆排序简介

1.1 什么是堆排序?

堆排序是一种基于堆数据结构的排序算法,具有稳定性和较高的性能。它分为建堆和排序两个阶段,通过利用堆的性质在O(n log n)时间内完成排序。

1.2 堆排序的应用场景 

堆排序在实际应用中广泛用于大数据集合的排序,以及需要动态维护最大(或最小)元素的场景,比如实时系统中的任务调度

 2. 建堆过程

2.1 堆的基本概念回顾

在开始深入堆排序之前,我们先回顾一下堆的基本概念,包括大堆和小堆的定义

堆是一种特殊的树形数据结构,它满足以下两个基本性质:

  1. 堆的完全二叉树性质: 堆是一棵完全二叉树,即除了最后一层,其他层都是满的,并且最后一层的节点尽量靠左排列。

  2. 堆序性质: 对于每个节点i,父节点的值总是大于等于(大堆)或小于等于(小堆)其子节点的值。

堆可以分为两种类型:大堆和小堆。它们的区别在于堆序性质的不同。

  • 大堆(Max Heap): 在大堆中,每个节点的值都大于等于其子节点的值。根节点是堆中的最大值。

  • 小堆(Min Heap): 在小堆中,每个节点的值都小于等于其子节点的值。根节点是堆中的最小值。

通过这种特殊的堆结构,堆排序能够高效地进行升序(小堆)或降序(大堆)排序。

理解了堆的基本概念后,我们将深入探讨堆排序的建堆过程、排序过程以及可能的性能优化。让我们继续阐述堆排序的实现和优化方法。

2.2 第一种建堆方法:向上调整

以下是第一种方法 我们采用向上调整  先进行建堆

void HeapSort(int* a, int n)
{
	//第一种 向上调整 小堆
	for (int i = 1; i < n; i++)
	{
		Adjustup(a, i);
	}//建堆


}

 接下来填写我们的测试用例

int main()
{
	int a[] = { 4,6,7,2,8,4,9 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d",a[i]);
	}
	return 0;
}

2.3 代码实例:建立小堆的问题 

 要理解堆排序不麻烦

堆排序的特点是可以帮助我们选树  是一种选择排序

但有个问题 我们现在要排的是升序  建的是大堆还是小堆呢

结论:大堆

先看看我们先前排序的逻辑结构

 物理上是一个数组

 如果我们说升序选择是建小堆,那我们就是要选择出最小数 那么我们如何选出次小的树呢

也就是说我们第一个数是最小的不用动 剩下的重新建堆

 剩下的树有可能是堆,也有可能不是堆

为什么这么说呢  因为他们之间的关系已经全部被打乱 原先的结构改变了

只能重新建堆   那么代价就有些大 复杂度  建堆时间复杂度是  N*logN

所以他的时间复杂度就是N^2 * logN

所以建小堆进行排序是不可取的 

 所以

我们采用建大堆的方法

3. 排序过程

3.1 选择建大堆的原因

在进行堆排序时,我们选择建立大堆而不是小堆的主要原因在于效率。建立小堆可能会导致在排序的过程中需要不断地进行调整,增加了时间复杂度。相比之下,建立大堆的方式更为高效,可以降低整体的时间复杂度。

3.1.1 大堆的优势

  • 减少调整次数: 建立大堆时,较大的元素会逐渐上浮到堆顶,不容易被后续较小的元素打乱。因此,后续的调整次数相对较少,提高了效率。

  • 避免元素关系破坏: 在建立小堆的过程中,元素之间的关系可能被打乱,导致需要额外的调整操作。而建立大堆时,元素关系的破坏相对较小,减少了重新调整的需求。

 

3.2 代码优化:建大堆方式

为了改进建堆的方式,我们对原有的建堆代码进行轻微的修改,以建立大堆。

我们先轻微改动一下代码

 

 

 

3.2.1 优化的核心思想

  • 自底向上调整: 从堆的中间位置开始向根节点遍历,对每个节点进行向下调整。这样可以确保在调整的过程中,较大的元素逐渐下沉到堆的底部。

  • 适应大堆排序: 建立大堆后,排序过程将更加高效,不需要频繁调整元素位置。

3.3 排序实现详解

排序的实现主要分为两个步骤:建堆和排序。

3.3.1 建大堆

在建立大堆的过程中,我们将数组转化为一个有效的大堆结构。

3.3.2 排序

排序阶段利用了堆的性质,每次将堆顶元素(最大元素)与堆的最后一个元素交换,然后对剩余的堆进行调整,确保剩余部分仍然是一个大堆。重复这个过程,直到整个数组有序。

 

 此时我们建成了一个大堆

我们让其首尾交换 并不将最后一个数看作堆里的内容

 此时左右各是一个大堆 将树进行向下调整 选出次大的数是8  再将8与倒数第二个进行交换 再进行向下调整

 

 

 最后时间复杂度就是  n*logN 效率十分高

 

4. 性能分析与优化

4.1 时间复杂度分析

堆排序的时间复杂度主要分为两个部分:建堆的时间复杂度和排序的时间复杂度。

4.1.1 建堆的时间复杂度

在建堆阶段,我们采用了自底向上的方式建立大堆,其时间复杂度为 O(n*logN),其中 n 是数组的大小。这是因为我们只需对堆的一半元素进行向下调整,而堆的一半元素之后都是叶子节点,不需要调整。

4.1.2 排序的时间复杂度

在排序阶段,每次将堆顶元素与最后一个元素交换,并调整堆。因为堆的高度是logn,所以每次调整的时间复杂度是logn,总的排序时间复杂度为 O(nlogn)。

综合考虑建堆和排序阶段,堆排序的总体时间复杂度为 O(n+nlogn)=O(nlogn)。

4.2 选择建大堆的原因

选择建大堆的主要原因在于优化排序过程。通过建大堆,我们能够减少调整的次数,提高整体的排序效率。

4.2.1 优势总结
  • 较少调整次数: 大堆的建立方式使得较大的元素逐渐上浮到堆顶,减少了后续调整的次数。

  • 避免元素关系破坏: 相较于建小堆,建大堆时元素关系的破坏相对较小,降低了重新调整的需求。

4.3 优化方案与实践

在实现中,通过调整建堆的方式,我们采用了自底向上的方法建立大堆。这一优化方案在实践中表现出色,有效减少了整体的时间复杂度。

4.3.1 自底向上的建堆

通过遍历堆的一半元素,从底部向上进行调整,我们有效地建立了一个大堆。这一方法的实际效果在于减少了调整的次数,提高了建堆的效率。

4.3.2 选择建大堆的实践

在排序过程中,我们通过选择建立大堆的方式,使得排序阶段的调整次数减少,大大提高了排序的效率。这一实践得以验证,使得堆排序在实际应用中具有更好的性能表现。

在接下来的部分,我们将设计测试用例并分析实验结果,以验证堆排序的正确性和性能。

在堆排序中,建堆阶段通常使用向下调整(也叫做下沉、下调)的方式。这是因为向下调整相对于向上调整更为高效。

让我们来看一下向下调整的主要优势:

  1. 高效性: 向下调整可以在一次遍历中将一个无序的数组转化为堆结构。相比之下,向上调整可能需要多次遍历来达到相同的效果。

  2. 自底向上: 向下调整是自底向上的过程,从数组的中间位置开始,直至叶子节点。这种自底向上的方式使得调整的效率更高,因为在数组中较小的元素会逐渐沉到底部。

  3. 实现简单: 向下调整的实现相对简单直观,通常需要比向上调整更少的代码。

尽管向上调整也可以用于建堆,但通常情况下,向下调整被认为更为经典和高效。因此,在堆排序中,建堆阶段一般选择向下调整的方式,而排序阶段使用向上调整。这种组合使得整个堆排序算法在时间复杂度和实现复杂度上都能达到较好的平衡。

 

void HeapSort(int* a, int n)
{
	//第一种 向上调整 大堆
	//for (int i = 1; i < n; i++)
	//{
	//	Adjustup(a,i);
	//}//建堆
	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[] = { 4,6,7,2,8,4,9 };
	HeapSort(a, sizeof(a) / sizeof(int));
	for (int i = 0; i < sizeof(a) / sizeof(int); i++)
	{
		printf("%d",a[i]);
	}
	return 0;
}

 

5.2 未来的优化方向

尽管堆排序已经在很多方面取得了较好的性能,但在一些特定场景下,仍然存在一些可以进一步优化的空间。

5.2.1 多线程优化

在大规模数据集的排序中,考虑通过多线程并行处理来提高排序的速度,充分利用现代计算机的多核架构。

5.2.2 内存局部性优化

对于大规模数据集,可以考虑优化算法以提高内存局部性,减少缓存未命中,从而进一步提高排序性能。

5.2.3 适用性扩展

尝试将堆排序与其他排序算法结合,形成一种更为适用于多样化数据特征的混合排序策略,以提高算法的适用性。

综上所述,堆排序作为一种高效的排序算法,在实际应用中仍具有重要地位。随着计算机硬件和算法优化的不断发展,堆排序可能在更多场景中发挥其优势。未来的研究方向包括算法并行化、内存局部性优化等方面的探索,以进一步提高堆排序的性能。

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

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

相关文章

Vue生命周期

生命周期 Vue.js 组件生命周期&#xff1a; 生命周期函数&#xff08;钩子&#xff09;就是给我们提供了一些特定的时刻&#xff0c;让我们可以在这个周期段内加入自己的代码&#xff0c;做一些需要的事情; 生命周期钩子中的this指向是VM 或 组件实例对象 在JS 中&#xff0c;…

JRT实现缓存协议

上一篇介绍的借助ORM的增、删、改和DolerGet方法&#xff0c;ORM可以很精准的知道热点数据做内存缓存。那么就有一个问题存在&#xff0c;即部署了多个站点时候&#xff0c;如果用户在一个Web里修改数据了&#xff0c;那么其他Web的ORM是不知道这个变化的&#xff0c;其他Web还…

局部性原理和伪共享

CPU Cache CPU Cache可以理解为CPU内部的高速缓存。CPU从内存读取数据时&#xff0c;将要读取的数据及其相邻地址的数据&#xff0c;即至少一个Cache Line&#xff0c;写入Cache&#xff0c;以便后续访问时提高读取速度。 CPU存在多级Cache&#xff0c;级别最高的离CPU最近&a…

实现电商平台与营销系统无缝集成:雅座的无代码开发与API连接

无代码开发&#xff1a;营销的新引擎 在数字化转型的浪潮中&#xff0c;无代码开发已成为企业提升效率、减少成本的新引擎。这种开发方式允许非技术人员通过图形界面构建应用程序&#xff0c;无需编写代码即可实现复杂功能。这对于营销、广告推广以及用户运营等业务尤为重要&a…

贪心 53. 最大子序和 122.买卖股票的最佳时机 II

53. 最大子序和 题目&#xff1a; 给定一个数组&#xff0c;有正有负&#xff0c;找出一个连续子序列的总和最大&#xff08;子数组最少一个&#xff09; 暴力思路&#xff1a; 双层for循环&#xff0c;记录每一次可能的子序列的总和&#xff0c;初始为整数最小值&#xff…

Go语言实现大模型分词器tokenizer

文章目录 前言核心结构体定义构造函数文本初始处理组词构建词组索引训练数据编码解码打印状态信息运行效果总结 前言 大模型的tokenizer用于将原始文本输入转化为模型可处理的输入形式。tokenizer将文本分割成单词、子词或字符&#xff0c;并将其编码为数字表示。大模型的toke…

ArkTS-取消标题与自定义标题栏

文章目录 取消标头自定义标题栏导入Resources自定义跳转动画关于底部tabBar导航文本输入(TextInput/TextArea)自定义样式添加事件可以是onChange可以是onSubmit List列表组件设置主轴方向 网格布局服务卡片-获取地理位置页面获取地理位置服务卡片获取地理位置 可以先看看&#…

wvp 视频监控平台抓包分析

抓包时机 下面的抓包时机是抓包文件最新&#xff0c;但是最有用的包 选择网卡开始抓包 如果之前已经选择网卡&#xff0c;直接开始抓包 停止抓包 重新抓包 sip播放过程分析 过滤条件 tcp.port 5060 and sip 可以看到有这些包 选择任何一个 &#xff0c;戍边右键--追踪流--…

【批处理常用命令及用法大全】

文章目录 1 echo 和 回显控制命令2 errorlevel程序返回码3 dir显示目录中的文件和子目录列表4 cd更改当前目录5 md创建目录6 rd删除目录7 del删除文件8 ren文件重命名9 cls清屏10 type显示文件内容11 copy拷贝文件12 title设置cmd窗口的标题13 ver显示系统版本14 label 和 vol设…

加密挖矿、AI发展刺激算力需求激增!去中心化算力时代已来临!

2009年1月3日&#xff0c;中本聪在芬兰赫尔辛基的一个小型服务器上挖出了比特币的创世区块&#xff0c;并获得了50BTC的出块奖励。自加密货币诞生第一天起&#xff0c;算力一直在行业扮演非常重要的角色。行业对算力的真实需求&#xff0c;也极大推动了芯片厂商的发展&#xff…

matlab三维地形图

matlab三维地形图 %%%%—————Code to draw 3D bathymetry—————————— %-------Created by bobo,10/10/2021-------------------- clear;clc;close all; ncdisp E:\data\etopo\scs_etopo.nc filenmE:\data\etopo\scs_etopo.nc; londouble(ncread(filenm,lon)); lat…

【深度学习笔记】06 softmax回归

06 softmax回归 softmax运算损失函数对数似然Fashion-MNIST数据集读取数据集读取小批量整合所有组件 softmax回归的从零开始实现初始化模型参数定义softmax操作定义模型定义损失函数分类精度训练预测 softmax回归的简洁实现 softmax运算 softmax函数能够将未规范化的预测变换为…

C语言——实现一个计算m~n(m<n)之间所有整数的和的简单函数。

#include <stdio.h>int sum(int m, int n) {int i;int sum 0;for ( i m; i <n; i){sum i;}return sum;}int main() { int m, n;printf("输入m和n&#xff1a;\n");scanf("%d,%d", &m, &n);printf("sum %d\n", sum(m, n)…

每日一题:LeetCode-202.面试题 08.06. 汉诺塔问题

每日一题系列&#xff08;day 07&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

一款LED段码显示屏驱动芯片方案

一、基本概述 TM1620是一种LED&#xff08;发光二极管显示器&#xff09;驱动控制专用IC,内部集成有MCU数字接口、数据锁存器、LED驱动等电路。本产品质量可靠、稳定性好、抗干扰能力强。 二、基本特性 采用CMOS工艺 显示模式&#xff08;8段6位&#xff5e;10段4位&#xff…

【寒武纪(6)】MLU推理加速引擎MagicMind,最佳实践(二)混合精度

混合精度在精度损失范围内实现数倍的性能提升。 支持的量化特性 构建混合精度的流程 构建混合精度的流程如下&#xff0c;支持浮点或半精度编程&#xff0c;以及量化精度编程两种方式。 浮点或半精度 无需提供tensor分布量化编程需要设置tensor分布。 网络粒度和算子粒度的设…

LVS-NAT实验

实验前准备&#xff1a; LVS负载调度器&#xff1a;ens33&#xff1a;192.168.20.11 ens34&#xff1a;192.168.188.3 Web1节点服务器1&#xff1a;192.168.20.12 Web2节点服务器2&#xff1a;192.168.20.13 NFS服务器&#xff1a;192.168.20.14 客户端&#xff08;win11…

智能优化算法应用:基于布谷鸟算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于布谷鸟算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于布谷鸟算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.布谷鸟算法4.实验参数设定5.算法结果6.参考文献7.…

Unity中Shader变体优化

文章目录 前言一、在Unity中查看变体个数&#xff0c;以及有哪些变体二、若使用预定义的变体太多&#xff0c;我们只使用其中的几个变体&#xff0c;我们该怎么做优化一&#xff1a;可以直接定义需要的那个变体优化二&#xff1a;使用 skip_variants 剔除不需要的变体 三、变体…

TikTok如何破解限流?真假限流如何分辨?速来自测

Tiktok是目前增长较快的社交平台&#xff0c;也是中外年轻一代首选的社交平台&#xff0c;许多出海品牌已经看到了TikTok营销的潜力&#xff0c;专注于通过视频、电商入驻来加入TikTok这片蓝海&#xff0c;加深品牌影响力&#xff0c;获得变现。 然而TikTok新手往往都会遇到一…