《算法导论》代码搬运工--堆排序

算法导论第六章6.3建堆和6.4堆排序算法课后答案 6.3-2 在BUILD-MAX-HEAP的第2行代码中,为什么希望循环下标i从向下取整leghth[A]/2降到1,而 不是从1升到向下取整leghth[A]/2? 因为如果用递增循环从下标i=1开始,那么i的两个左右子树对于任意排序的数组来说就可能出现 左右子树不是最大堆的情况(使用MAX-HEAPIFY(A,i)函数必须满足左右子树是最大堆)。     如果用递减循环从下标i 阅读详情

最近买了本中文版的《算法导论》,打算系统的看一下基础的算法,并尽量的实现一下书上的代码例子。书很厚,内容很多,有简单的也有难懂的,所以打算开一个新的系列,长期不定时的加入新的内容,就叫《算法导论》代码搬运工系列。代码基本都是用java实现的,实现语言并不重要,java和C的语法差别也并不大。

这一篇来搬运一个基础的排序算法:堆排序。

堆排序:顾名思义,就是用堆来实现排序的功能,那么在堆排序之前就先要知道什么是堆,怎么建堆。

《算法导论》中用数组来表示一个堆(二叉堆),如下图,那么堆中元素和元素之间的关系就需要使用数组下标来维护了,对一个二叉堆,用层序来依次存储到一维数组中,那么对于一个下标为 i 的元素a[i],它的parent(i)节点可以表示为a[i/2],当然i/2是取floor,左孩子left(i)可以表示为a[i*2],右孩子right(i)可以表示为a[i*2+1](注意下标不越界)。其他堆的性质就很简单了,例如最大堆,那么父亲节点的值一定是大于等于两个孩子节点的值的。


对于堆排序,有三种基本的操作:max-heapify, build-max-heap, heapsort,依次是最大化一个堆(只能针对当前堆,对于当前堆影响不到的其他子堆,算是一次原子操作--我自己的理解),建立一个完整的最大堆(对于一个堆的很多次max-heapify操作,使得整个堆成为最大/最小堆),以及最后的利用堆来排序。

下面是三种操作的java代码:

max-heapify:

public void max_heapify(int a[], int index, int heap_size) {
		int left_index = index * 2;
		int right_index = index * 2 + 1;
		int largest = index;
		if (left_index < heap_size && a[left_index] > a[index])
			largest = left_index;
		if (right_index < heap_size && a[right_index] > a[largest])
			largest = right_index;
		if (largest != index) {
			int temp = a[index];
			a[index] = a[largest];
			a[largest] = temp;
			max_heapify(a, largest, heap_size);
		}
	}
过程就是,找出当前节点和它左右孩子中最大的那个,如果最大的不是自己,那么和自己交换,并且对被交换那个下标递归执行当前步骤(之前有过一个困惑,我以为应该对下标为index的做递归,其实要注意到这里的largest下标是固定的,而其中的元素被改变了,所以针对的递归对象应该是以下标为准)。
build-max-heap:

int a[] = { Integer.MIN_VALUE, 16, 4, 10, 14, 7, 9, 3, 2, 8, 1 };
		Heap_sort hs = new Heap_sort();
		int heap_size = a.length;
		// 因为下标n/2+1后面的元素都是叶节点,所以只要从非叶节点开始往下遍历就可以,叶子节点没有必要遍历
		for (int i = heap_size / 2; i >= 1; i--) {
			hs.max_heapify(a, i, a.length);
		}
因为0下标需要额外判断,不如让有效内容从下标1开始,然后对非叶子节点进行遍历执行max-heapify操作,因为叶子节点没有孩子,所以没有必要去遍历,又由于二叉堆是完全二叉树,所以下标n/2后面的节点都是叶子节点。

heapsort:

public void heap_sort(int a[]) {
		int heap_size = a.length;
		for (int i = a.length - 1; i > 1; i--) {
			int temp = a[i];
			a[i] = a[1];
			a[1] = temp;
			heap_size--;
			max_heapify(a, 1, heap_size);
		}
	}
注意到前面的max-heapify有一个参数是heap_size,如果不牵涉到排序,那么这个参数就一直是数组的length,但是如果牵涉到排序,这个有效length是会变的。因为堆排序的过程是这样的:根据大顶堆的性质,堆顶元素,也就是根节点的值一定是最大的,所以每一次都把堆顶元素和最后一个叶子节点交换,再把这个堆顶元素从堆里面踢出去放在这个数组的末尾,然后把原来的堆最大化,那么下一个最大的元素又冒出来了,再做一样的动作直到堆中元素都被按照顺序排列到数组中,这个数组就是这一堆数字的升序排列(降序只需要做一个小顶堆即可)。

再提一下每一个排序算法都很关注的时间复杂度,堆排序的时间复杂度是O(nlgn),因为并不需要额外的空间,所以空间复杂度一直都是常数级,是原址排序(就地排序)。

在练习题中,有两道证明题,一个是证明在最坏情况下,堆排序的时间复杂度是Ω(nlgn),另一个是证明在所有元素都不同的情况下,堆排序的时间复杂度是Ω(nlgn),不去深究如何证明,但是可以知道堆排序的时间复杂度的数量级一直是nlgn的。对于O, Ω和Θ的定义可以去翻一下数学书,对于一个算法的时间复杂度的界的定义,但是不去特别深究也问题不大。



算法导论源码 学习算法导论怎么可以不编程 这是算法导论里的源码 供参考 C++实现 立即下载

相关推荐

算法导论 源代码 C语言实现

算法导论 源代码 C语言实现

菜鸟学习从入门到放弃(二)排序算法总结与应用(附代码)

排序算法总结

CCF_优快云的博客 860

算法导论(含源码)C语言班

算法导论C语言版本。下载后绝对不会后悔。嗯。谢谢

AI时代程序员核心价值迁移:从写代码到定义系统契约

在AI辅助编程成为标配的今天,'写代码'本身正快速退化为低门槛操作,而真正决定技术人不可替代性的,是理解业务本质、建模系统约束、保障跨环境可信度的能力。本文聚焦程序员能力重构的关键跃迁——如何将模糊需求精准翻译为可执行的技术契约,如何在微服务与多端协同中设计失败边界与可观测性协议,以及如何以‘体验建筑师’视角平衡算法精度与真实用户认知负荷。结合金融风控、医疗SaaS等一线实战案例,解析AI生成代码背后的许可证风险、性能幻觉与文档失真等典型暗礁,并提供可立即落地的逆向工程训练、技术决策日志与可信度四象限评估法

weixin_33794672的博客 387

算法导论C++源代码

算法导论第二版,C++源代码,mit的那本经典教材

CLRS:算法导论的源代码

Pseudcode的源代码,以及算法介绍的解决方案 我的编译器是Apple LLVM版本6.1.0(clang-602.0.53)(基于LLVM 3.6.0svn)目标:x86_64-apple-darwin14.3.0线程模型:posix

算法与数据结构系统学习指南:从基础到实践,构建算法思维

算法与数据结构是计算机科学的核心基础,其本质是高效组织和处理数据的方法论。从数组、链表、栈、队列等线性结构,到树、图、哈希表等非线性结构,每种数据结构都有其特定的操作逻辑与时空复杂度。理解这些原理是进行算法设计与分析的前提。算法的价值在于将复杂问题分解,通过排序、搜索、递归、分治、动态规划、贪心、回溯等思想,找到最优或可行的解决方案,从而提升程序的效率与性能。在实际应用中,无论是技术面试中的经典问题,还是日常开发中的系统设计,如Redis数据结构的选择或工业异常检测算法的实现,扎实的算法功底都至关重要。本文

weixin_33766168的博客 327

算法导论第三版各种数据结构的c/c++源代码

请参考算法导论第三版英文版Introduction to Algorithms 3rd Edition,本程序为第10章到第14章常用数据结构的c/c++实现。 IDE环境为vc++ 6.0。 主要包括: 队列 双向链表 哈希表 二叉搜索树

《算法导论的Java实现》 7 堆排序

《算法导论的Java实现》的第7章----堆排序

chen09的专栏 3842

堆排序(C#,C++)算法导论

算法导论第三版第六章内容,作者使用C#与C++两种编程语言实现

算法导论代码

算法导论Designing Object Oriented C++ Designing Object Oriented C++ Applications Designing Object Oriented C++ Applications

算法导论第六章:堆排序

堆排序是一种原地(in place)排序算法。堆排序还引入另一种算法设计技术,利用某种数据结构来管理算法执行中的信息,堆数据结构不仅在排序中有用,还可以构成一个有效的优先队列。6.1 堆(二叉)堆数据结构是一种数组对象,如图6-1所示,它可以被视为一颗完全二叉树,树中的每个节点与数组中存放该节点值的那个元素对应。树的每一层都是填满的,最后一层可能除外。堆A具有两个属性:length[A]是数组中的元素个数,heap-size[A]是存放在A中的堆的]元素个数。也就是说虽然A[1...length[A]]都可

longhuihu的专栏 4954

机器人强化学习入门学习笔记

如果你追求高精度动力学仿真、用于强化学习或机器人研究,MuJoCo 是一个非常优秀的选择。如果需要快速实验、使用真实机器人模型,PyBullet 或 Gazebo可能更合适;如果你追求大规模并行训练,Isaac Gym 或 BraX会更高效。legged gym底层是​编辑isaacgym,基于gpu训练可以多环境并行训练,收敛到一个稳定行走的策略快。本视频MuJoCo基于cpu训练很慢。

xiaomu_347的博客 1462

《算法导论读书笔记》第二部分 第六章 堆排序

第二部分 排序和顺序统计量 这一部分介绍了几种解决如下排序问题的算法: 即输入n个数的序列,输出排列好的序列 数据的结构 名词:记录(record),关键字(key),卫星数据(satellite data) … 为什么要排序 很多计算机科学家认为排序是算法研究中最基础的问题,其原因有很多: 有时应用本身就需要对信息进行排序。 很多算法通常把排序作为关键子程序。 现有的排序算法数量非常庞大,其中所使用的技术也非常丰富。 我们可以证明排序问题的一个非平凡下界(在第8章中,我们会给出证明.

wg_cheeky的博客 1853

DC-DC电源PCB布局实战:从EMI优化到热管理

本文深入探讨了DC-DC电源PCB布局的核心实战技巧。文章从分析电流环路入手,强调通过优化“黄金三角”布局以最小化环路面积,从而有效抑制EMI并提升效率。详细阐述了功率器件摆放、地线分割、敏感信号布线、电感下方铺铜策略以及热管理设计等关键步骤,为工程师提供了一套从理论到实践的完整布局指南。

z5a6b的博客 721

全网最全 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置

昨天(2024年7月23日)我们分享了学生及科研人员电脑配置推荐 | 笔记本+外置显卡配置,性能足够支持完成你博士论文文本内容,那么今天我们就分享一文解决 | Linux(Ubuntn)系统安装 | 硬盘挂载 | 用户创建 | 生信分析配置的教程,我们使用一文来解决大家在做生信时遇到安装系统、配置环境的问题。在此文中,我们尽快可能给出一套全网最全的教程。目标是解决新手小白同学查资源的困惑和难题。但是,每个童鞋遇到的问题不一样,此教程也不可能把你遇到的每个问题都归纳在其中。我们也希望,

BioinfoDu 2260

第六章 堆排序习题

6.1堆 堆节点的高度:为该节点到叶节点最长简单路径上#边的个数#。(因此,根节点所在位置高度为0) 6.1-1 在高度为h的堆中,元素个数最多和最少分别是多少?最多:2h+1−1最少:2h最多:2^{h+1}-1 \\最少:2^h6.1-2 证明:含n个元素的堆的高度为⌊lgn⌋\lfloor \lg n \rfloor。证明:1)利用上面式子反推 2)数学归纳法证明即可 6.1-3

u012889441的博客 1万+

深入浅出块I/O子系统(四)请求处理过程

BIO请求处理的流程 函数scsi_request_fn()代码(摘自文件drivers/scsi/scsi_lib.c) (1)static void scsi_request_fn(struct request_queue *q) (2)int scsi_dispatch_cmd(struct scsi_cmnd *cmd) { host->hostt->queuecommand(host, cmd) } (3)struct sas_internal *i sas_queuec

sinat_37817094的博客 1348

[算法导论-分治策略]求最大子数组之各种解法及源代码实现

/* 问题: 已知数组 A = {2,4,-1,-5,3,-4,2,-6,4,1,2,2,4,-2,2}; 求: 最小子数组和 分析: 一:  分治法:把问题分解成若干个简单易解的小问题,最后再把小问题归并起来,找到我们原来要解决问题的解 本问题中,我们把问题分解成两个规模尽量相等的子问题。 A[low...mid] 和 A[mid+1...high] 那最小的子数组

Ubuntu装机必备 750

Feature ‘alsa‘ was enabled, but the pre-condition ‘config.unix && !config.qnx && libs.alsa‘ failed解决

这个问题主要是Qt多媒体插件中缺少了ALSA音频库,所以我们需要自行先编译ALSA 在执行./configure的时候,配置项中ALSA为no Qt Multimedia: ALSA ................................... no GStreamer 1.0 .......................... no GStreamer 0.10 ......................... no Video for Linux .............

有问题或资源连接有缺失的可以私信公众号新潮看世界获取 2587

Python控制Keysight DAQ973A/DAQ970A实现数据采集

本文介绍了如何通过编程实现Keysight DAQ973A数据采集系统的自动化温度测量。首先,通过GPIB线将PC与仪器连接,并使用热电耦测量线连接被测装置。接着,通过查阅Keysight官网提供的编程手册,获取了实现温度测量所需的SCPI指令。然后,使用pyvisa库编写代码,与仪器进行交互,发送SCPI指令并读取测量结果。代码中整合了配置和查询指令,并将测量结果转换为浮点数格式。最后,将整个流程封装为命令行工具,用户可以通过配置文件设置参数,并执行自动化测试,测试结果将保存为CSV文件。整个过程实现了温

xgh1951的博客 1887
上一篇: BitMap算法
下一篇: 搭mongodb+zookeeper+kafka环境
MR_LUXY
博客等级 码龄16年 20粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值