排序算法:堆排序,golang实现

news2024/11/23 19:22:14

目录

前言

堆排序

代码示例

1. 算法包

2. 堆排序代码

3. 模拟程序

4. 运行程序

5. 从大到小排序

堆排序的思想

堆排序的实现逻辑

1. 构建最大堆

2. 排序

循环次数测试

假如 10 条数据进行排序

假如 20 条数据进行排序

假如 30 条数据进行排序

假设 5000 条数据,对比 冒泡、选择、插入、快速、归并

堆排序的适用场景

1. 大数据集排序

2. 外部排序

3. 优先级队列

4. 动态数据排序


前言

在实际场景中,选择合适的排序算法对于提高程序的效率和性能至关重要,本节课主要讲解"堆排序"的适用场景及代码实现。

堆排序

堆排序(Heap Sort)是一种基于比较的排序算法,它利用堆这种数据结构所设计。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。在堆排序算法中,我们通常采用最大堆(每个父节点的值都大于或等于其子节点的值)来进行排序。

代码示例

下面我们使用Go语言实现一个堆排序

1. 算法包

创建一个 pkg/algorithm.go

mkdir pkg/algorithm.go

如果看过上节课的快速排序,则已存在该文件,我们就不需要再创建了

2. 堆排序代码

打开 pkg/algorithm.go 文件,代码如下

从小到大 排序

package pkg

// BubbleSort 冒泡排序
...

// SelectionSort 选择排序
...

// InsertionSort 插入排序
...

// QuickSort 快速排序
...

// partition 分区操作
...

// HeapSort 堆排序
func HeapSort(arr []int) {
	n := len(arr)

	// 构建最大堆
	for i := n/2 - 1; i >= 0; i-- {
		heapify(arr, n, i)
	}

	// 一个个从堆顶取出元素
	for i := n - 1; i >= 0; i-- {
		// 移动当前根到末尾
		arr[i], arr[0] = arr[0], arr[i]

		// 调用 max heapify on the reduced heap
		heapify(arr, i, 0)
	}
}

// heapify 将以 i 为根的子树调整为最大堆
func heapify(arr []int, n int, i int) {
	largest := i // 初始化最大为根
	l := 2*i + 1 // 左子节点
	r := 2*i + 2 // 右子节点

	// 如果左子节点大于根
	if l < n && arr[l] > arr[largest] {
		largest = l
	}

	// 如果右子节点大于当前的最大值
	if r < n && arr[r] > arr[largest] {
		largest = r
	}

	// 如果最大值不是根
	if largest != i {
		arr[i], arr[largest] = arr[largest], arr[i] // 交换

		// 递归地堆化受影响的子树
		heapify(arr, n, largest)
	}
}

3. 模拟程序

打开 main.go 文件,代码如下:

package main

import (
	"demo/pkg"
	"fmt"
)

func main() {
	// 定义一个切片,这里我们模拟 10 个元素
	arr := []int{84, 353, 596, 848, 425, 849, 166, 521, 228, 573}
	fmt.Println("Original data:", arr) // 先打印原始数据
	pkg.HeapSort(arr)                  // 调用堆排序
	fmt.Println("New data:  ", arr)    // 后打印排序后的数据
}

4. 运行程序

go run main.go

能发现, Original data 后打印的数据,正是我们代码中定义的切片数据,顺序也是一致的。

New Data 后打印的数据,则是经过堆排序后的数据,是从小到大的。

5. 从大到小排序

如果需要 从大到小 排序也是可以的,在代码里,需要将两个 if 判断比较的 符号 进行修改。

修改 pkg/algorithm.go 文件:

package pkg

// BubbleSort 冒泡排序
...

// SelectionSort 选择排序
...

// InsertionSort 插入排序
...

// QuickSort 快速排序
...

// partition 分区操作
...

// HeapSort 堆排序
func HeapSort(arr []int) {
	n := len(arr)

	// 构建最大堆
	for i := n/2 - 1; i >= 0; i-- {
		heapify(arr, n, i)
	}

	// 一个个从堆顶取出元素
	for i := n - 1; i >= 0; i-- {
		// 移动当前根到末尾
		arr[i], arr[0] = arr[0], arr[i]

		// 调用 max heapify on the reduced heap
		heapify(arr, i, 0)
	}
}

// heapify 将以 i 为根的子树调整为最大堆
func heapify(arr []int, n int, i int) {
	largest := i // 初始化最大为根
	l := 2*i + 1 // 左子节点
	r := 2*i + 2 // 右子节点

	// 如果左子节点小于根
	if l < n && arr[l] < arr[largest] {
		largest = l
	}

	// 如果右子节点小于当前的最大值
	if r < n && arr[r] < arr[largest] {
		largest = r
	}

	// 如果最大值不是根
	if largest != i {
		arr[i], arr[largest] = arr[largest], arr[i] // 交换

		// 递归地堆化受影响的子树
		heapify(arr, n, largest)
	}
}

只需要一丁点的代码即可

从 package pkg 算第一行,上面示例中在第四十四行代码,第四十九行代码,我们将 ">" 改成了 "<" ,这样就变成了 从大到小排序了

堆排序的思想

  • 利用堆的性质:堆排序利用堆的性质,通过不断调整堆来使得每次都能从堆顶取出当前序列的最大(或最小)元素,从而达到排序的目的
  • 原地排序:堆排序是一种原地排序算法,它只需要用到 O(1) 的额外空间来进行排序(除了输入的数组外,不需要使用其他数据结构)
  • 不稳定性:堆排序是一种不稳定的排序算法,因为在调整堆的过程中,可能会改变相同元素的相对顺序
  • 时间复杂度:堆排序的时间复杂度是 O(n log n),这主要来自于构建最大堆和每次调整堆的时间复杂度

堆排序的实现逻辑

堆排序主要分为两个步骤:

1. 构建最大堆

  • 将待排序的序列构造成一个最大堆,此时,整个序列的最大值就是堆顶的根节点
  • 构建最大堆的过程是从最后一个非叶子节点开始(即 n/2-1 位置,因为数组是从 0 开始索引的),对每个非叶子节点调用 heapify 函数,使其和其子树满足最大堆的性质

2. 排序

  • 将堆顶元素(最大值)与堆数组的末尾元素进行交换,此时末尾就是最大值
  • 由于堆的大小减少 1,我们再次将堆顶元素调整为最大值,以满足最大堆的性质
  • 重复这个过程,直到堆的大小为 1,算法结束

循环次数测试

参照上面示例进行测试(因考虑到每次手动输入 10 条、20 条、30 条数据太繁琐,所以我写了一个函数,帮助我自动生成 0到1000 的随机整数)

假如 10 条数据进行排序

总计循环了 32 

假如 20 条数据进行排序

总计循环了 79 

假如 30 条数据进行排序

总计循环了 136 

假设 5000 条数据,对比 冒泡、选择、插入、快速、归并

  • 冒泡排序:循环次数 12,502,499
  • 选择排序:循环次数 12,502,499
  • 插入排序:循环次数 6,323,958
  • 快速排序:循环次数 74,236 次
  • 堆排序:循环次数 59,589 次
  • 归并排序:循环次数 60,288 次

堆排序的适用场景

堆排序特别适用于以下场景

1. 大数据集排序

由于堆排序的时间复杂度是 O(n log n),在处理大数据集时效率较高

2. 外部排序

当数据太大,不能全部加载到内存时,可以使用堆排序进行外部排序,因为它只需要读取一次输入数据,然后逐步输出排序结果

3. 优先级队列

堆经常被用作优先级队列的实现方式,堆排序可以看作是从无序的优先队列中重建有序的优先队列的过程

4. 动态数据排序

当数据集合动态变化(如插入、删除操作频繁),堆排序的堆结构可以高效地维护数据的排序状态

总的来说,堆排序因其良好的最坏情况时间复杂度,以及对动态数据排序的友好性,在多种场景下都是非常有用的排序算法

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

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

相关文章

数据库——战德臣

1. 数据存储体系 1.1 计算机系统的存储体系 1.将不同性价比的存储组织在一起&#xff0c;满足高速的、大容量、低价格需求 2.CPU与内存直接交换信息&#xff0c;按存储单元&#xff08;存储字&#xff09;进行访问 3.外存按存储块进行访问&#xff0c;其信息先装入内存&…

NSSCTF-GDOUCTF 2023新生赛

[GDOUCTF 2023]hate eat snake 考察&#xff1a;js代码审计 打开题目&#xff0c;发现需要坚持60秒&#xff0c;那么简单的一个思路就是修改得分的变量>60即可 办法1&#xff1a;修改变量 右键查看源代码&#xff0c;之后发现有一个snake.js的文件&#xff0c;ctrlf搜索i…

健康小贴士丨中考考生怎么吃得好?

文章目录 引言三餐最佳的进食时间引言 中考正值初夏,气温急剧升高,食物易滋生细菌,发生食物中毒的风险也随之增加,医生建议 选择新鲜的食材,煮熟煮透,现吃现做,尽量不食用剩饭剩菜;不在路边露天摊点、不到无证和食品安全状况差的餐馆用餐;尽量减少在外就餐和点外卖的…

客服中心:高效知识库管理,6步提高70%用户体验

在当今快节奏的商业环境中&#xff0c;客服中心作为企业与客户沟通的重要桥梁&#xff0c;其运作的顺畅与否直接影响着客户的满意度和忠诚度。而知识库作为客服中心的核心资源之一&#xff0c;其管理水平的高低更是直接影响着客服的工作效率和问题解决能力。本文将深入探讨一系…

Django之JsonResponse对象

【图书介绍】《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》_django 5企业级web应用开发实战(视频教学版)-CSDN博客 《Django 5企业级Web应用开发实战&#xff08;视频教学版&#xff09;》(王金柱)【摘要 书评 试读】- 京东图书 (jd.com) 在Django框…

“LangChain实战:探索回调函数的应用

前言 毫无疑问&#xff0c;2024将是人工智能丰收年&#xff0c;开始寒假的我&#xff0c;准备先把LangChain捋一遍。 这篇文章来学习下callback机制&#xff0c; 之前聊过AutoGen的callback机制&#xff0c;我们来对比下。 回调和异步 作为js开发者&#xff0c;对于回调函数…

springboot智能健康管理平台-计算机毕业设计源码57256

摘要 在当今社会&#xff0c;人们越来越重视健康饮食和健康管理。借助SpringBoot框架和MySQL数据库的支持&#xff0c;开发智能健康管理平台成为可能。该平台结合了小程序技术的便利性和SpringBoot框架的快速开发能力&#xff0c;为用户提供了便捷的健康管理解决方案。 通过智能…

无线磁吸充电宝哪个牌子值得入手?什么牌子磁吸充电宝性价比高?

在当下科技日新月异的时期&#xff0c;无线磁吸充电宝成为了众多电子设备用户的得力助手。然而&#xff0c;面对市场上众多品牌和型号的无线磁吸充电宝&#xff0c;消费者常常陷入选择的困境&#xff1a;到底哪个牌子值得入手&#xff1f;什么牌子的磁吸充电宝性价比高&#xf…

【JavaScript】详解默认导出和命名导出的区别

文章目录 一、默认导出二、命名导出三、默认导出和命名导出的区别四、实际应用案例五、总结 在JavaScript模块化开发中&#xff0c;导入和导出模块是核心操作。ES6引入的模块化语法提供了两种主要的导出方式&#xff1a;默认导出&#xff08;default export&#xff09;和命名导…

【2024蓝桥杯/C++/B组/宝石组合】

代码来源2024第十五届蓝桥杯 C/CB组真题题解_蓝桥杯2024b组c语言答案-CSDN博客 证明s的简化式子

【Linux】命令行通配符

Linux在文件管理方面提供了丰富的功能&#xff0c;例如通配符&#xff0c;它是一种用于匹配文件名的特殊字符。通配符在Linux中可以帮助我们更加方便和快捷地查找和操作文件。 1.命令行通配符 通配符是一种特殊语句&#xff0c;主要有星号(*)、问号(?)等表示&#xff0c;用来…

记一个搞笑的自写类加载TemplatesImpl

今天没事想自己写个CC3类加载 结果为了顺利触发到TemplatesImpl#getTransletInstance的newInstance给我整急眼了&#xff0c;使劲改字段强行通过循环 结果搞了个下面的代码出来 import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apa…

手机买对不买贵!性价比之王再升级,致敬奋斗者

众所周知&#xff0c;比起旗舰机&#xff0c;中端机一年要发几次新款机型&#xff0c;因此&#xff0c;一两千元的价位段就尤其的卷。那此时作为消费者的我们就是赚了&#xff0c;花更少的钱就能买到更好的产品。华为畅享70S这款手机是今年最新的一款针对性价比用户推出的千元机…

大厂面试必备的软件测试八股文【附答案】

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 最近有很多粉丝问我&#xff0c;有什么方法能够快速提升自己&#xff0c;通过阿里、腾讯、字节跳动、京东等互联网大厂的面试&#xff0c;我觉得短时间提升…

7ECloud云服务器在视频流服务器中的应用

视频现在已然是人们之间互相传递的一种信息形式&#xff0c;而视频内容也是娱乐消费的主要形式之一&#xff0c;媒体平台想要提供高效&#xff0c;稳定的视频流服务也成为了行业关注的焦点之一。7ECloud云服务器展现出的计算能力&#xff0c;灵活的资源调度能力以及高度扩展性等…

【中项】系统集成项目管理工程师-第9章 项目管理概论-9.3项目经理的角色与9.4项目生命周期和项目阶段

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

C++ 位图

1. 位图概念 1. 面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在 这40亿个数中。【腾讯】 1. 利用map&#xff0c;set等容器存储遍历 2. 排序(O(NlogN))&#xff0c;利用二分查找: 但是其有40亿个数据&am…

骨传导耳机哪个牌子值得入手?精选五款2024热销骨传导耳机推荐!

随着健康意识的不断提升&#xff0c;运动健身已成为大众生活的热门选择&#xff0c;而人们对运动时音乐享受的需求也随之达到了新的高度。然而&#xff0c;许多运动达人在享受音乐律动的同时&#xff0c;却常被传统耳机易脱落、维护不便等问题所困扰&#xff0c;这无疑给他们的…

智能计算模拟:DFT+MD+ML深度融合及科研实践应用

第一性原理、分子动力学与机器学习三者的交汇融合已在相关研究领域展现强劲的研究热潮。借助第一性原理计算揭示材料内在的量子特性&#xff0c;并结合分子动力学模拟探究材料在实际环境下的动态行为&#xff1b;运用机器学习算法与上述方法结合&#xff0c;开发高性能预测模型…