学术诚信声明
本人郑重声明:本实践报告围绕课程项目文件夹中 46 号堆排序代码文件开展的分析、调试、优化及报告撰写工作,均为本人独立完成;过程中所使用的开发环境、辅助工具及参考资料已如实说明,未抄袭、剽窃任何个人或机构的成果,未篡改代码调试过程与实践结论,不存在任何学术不端行为。本报告成果的知识产权归本人所有,若存在学术诚信问题,本人愿承担全部责任。
摘要
本次实践选题源自课程项目文件夹中的46号堆排序代码文件,旨在通过实操剖析堆排序算法逻辑,解决代码潜在问题并完成技术报告。实践过程中,先搭建Windows 11+Dev-C++的开发环境,借助辅助工具开展工作;初始编译代码时,排查出堆类型混淆、编译器兼容性不足、数组越界等关键问题,随后逐一制定修正方案,优化堆调整逻辑、替换专用函数、修复边界风险,经反复调试使代码适配现代编译器并实现正确升序排序。后续深入理解代码四大核心流程(主程序、Heap_Sort、BuildHeap、Heapify),拓展实现VSCode项目管理与Gitee版本控制,最终完成完整技术报告。本次实践不仅夯实了堆排序算法理论基础,提升了代码调试、优化及项目管理的实践能力,更深刻体会到理论与实践结合的重要性,培养了严谨细致的编程态度,为后续算法学习与工程实践奠定了坚实基础。
1.选题与准备
1.1选题

在老师发布了项目文件夹后,我怀着好奇的心情打开了,简单了解后,我在155个文件中选择了46号,开始了一次奇妙的旅程。
1.2环境准备
操作系统:Windows 11 64位
IDE与编译器:Dev-c++
辅助工具:Gemini、知乎、CSDN、豆包等
2.编译调试过程
2.1初始编译及错误分析

初始编译后报错如上。
这段代码的核心是实现堆排序,但存在以下关键问题:
堆类型混淆:代码实际实现的是小项堆(父节点小于子节点),但输出注释写的是 "Big heap_sort"(大顶堆排序),逻辑描述与实际实现矛盾。
兼容性问题:clrscr()、getch()、exit(0) 是 DOS/TC 环境的函数,在现代编译器(如 GCC、MSVC)中无法直接运行。
数组越界风险:if (R[j]>R[j+1]&&j<m) j++; 中 j+1 可能超过 m,导致访问非法内存。
2.2错误修正
(1)错误类型:堆类型混淆(逻辑错误)
原始代码问题:子节点选择条件:if (R[j]>R[j+1]&&j<m) j++
修正方案:if (j < m && R[j] < R[j+1]) j++
修正说明:原代码选择更小的子节点(小顶堆逻辑),修正后选择更大子节点(大顶堆逻辑),匹配升序排序需求
(2)错误类型:堆类型混淆(逻辑错误)
原始代码问题:堆调整终止条件:if (temp<R[j]) break
修正方案:if (temp >= R[j]) break
修正说明:原代码为小顶堆终止条件(根节点小于子节点则终止),修正后为大顶堆终止条件(根节点大于等于最大子节点则终止)
(3)错误类型:注释逻辑矛盾
原始代码问题:输出注释:printf("\nThe sequence after Big heap_sort is:\n")
修正方案:printf("\nThe sequence after heap sort (ascending):\n")
修正说明:原代码实际为小顶堆排序,却标注“大顶堆排序”,修正后明确为“升序堆排序”,与大顶堆逻辑匹配
(4)错误类型:数组越界风险
原始代码问题:边界判断顺序错误:if (R[j]>R[j+1]&&j<m) j++
修正方案:调整为:if (j < m && R[j] < R[j+1]) j++
修正说明:原代码先判断数组元素,再判断下标范围,可能导致j=m时访问R[j+1](越界);修正后先判断下标,确保j+1≤m,避免越界
(5)错误类型:编译器兼容问题
原始代码问题:使用clrscr()清屏函数
使用getch()等待输入
使用exit(0)退出程序,未包含头文件
修正方案:移除clrscr(),保留printf提示语句
替换为getchar()(两次调用,吸收回车符)
用return 1替代exit(0),包含<stdlib.h>头文件
修正说明:clrscr()是DOS/TC专用函数,现代编译器(GCC/MSVC)不支持,移除后通过提示语 句优化交互
getch()为非标准函数,getchar()是C语言标准输入函数,适配现代编译环境
exit(0)需依赖<stdlib.h>,return 1更符合main函数标准退出逻辑,避免头文件依赖问题
2.3反复调试
经过改正错误与代码优化,成功对代码进行编译。
修正代码如下图:



编译并运行结果如下:

3.代码理解与重命名
3.1运行测试
该程序基于 C 语言实现大顶堆排序算法,核心功能为对用户输入的整数序列进行升序排序。程序启动后,先引导用户输入待排序元素个数(需满足 0<n≤255 的合法性条件),再接收具体整数存入数组(从 1 开始计数,适配堆的索引规则);随后通过 BuildHeap 函数从最后一个非叶子节点开始构建初始大顶堆,借助 Heapify 函数完成单棵子树的堆调整(确保父节点≥子节点);接着在 Heap_Sort 函数中,通过反复交换堆顶(最大值)与堆尾元素、调整剩余元素为大顶堆的循环,逐步将元素归入有序区,最终实现升序排序;排序完成后输出结果,等待用户输入回车后正常退出。程序优化后修复了原始代码的堆类型混淆、数组越界等问题,适配现代编译器,兼具排序正确性、环境兼容性与代码规范性,能高效处理普通无序、已排序、含重复元素等多种场景的排序需求,充分体现堆排序 O (nlog₂n) 的时间复杂度与 O (1) 的空间复杂度优势。
3.2代码解析
该代码有四个流程:主程序流程、Heap_Sort函数流程、BuildHeap函数流程、Heapify函数流程
程序启动后进入main函数,首先提示用户输入待排序元素个数n,并校验n是否满足0 < n ≤ MAX,若不合法则输出错误提示并退出程序;若合法则继续让用户输入n个元素存入数组R[1..n],接着输出原始序列,再调用Heap_Sort(n)函数触发堆排序。

Heap_Sort函数的执行分为两步,第一步是调用BuildHeap(n)构建初始大顶堆,第二步是执行排序循环。BuildHeap函数会从最后一个非叶子节点(下标为n/2)开始,向前遍历每一个非叶子节点,每次都调用Heapify(i, n)函数将以当前节点i为根的子树调整为大顶堆,直到遍历完所有非叶子节点,初始大顶堆就构建完成了。

之后Heap_Sort函数会初始化i = n,进入i > 1的循环,每次循环都会把堆顶元素R[1](也就是当前堆的最大值)和堆尾元素R[i]交换,把最大值固定到堆尾形成有序区,接着调用Heapify(1, i-1)函数,把剩余的1~i-1个元素重新调整为大顶堆,再执行i--缩小堆的范围,重复这个交换和调整的过程,直到i ≤ 1,堆排序就完成了。

其中Heapify函数是堆调整的核心,它会先暂存根节点值temp = R[s],再初始化j = 2*s指向根节点的左孩子,然后进入j ≤ m的循环,先判断j < m且左孩子值小于右孩子值,若是则让j指向右孩子,确保j始终指向值更大的子节点;接着判断temp ≥ R[j],若是则说明当前根节点已经满足大顶堆性质,直接跳出循环,若否则把R[j]的值赋给R[s],让子节点上移,再更新s = j、j = 2*s,继续向下调整;循环结束后,把暂存的temp值赋给R[s],完成以s为根的子树的大顶堆调整,之后返回调用它的函数。

当Heap_Sort函数执行完毕,main函数会输出排序后的升序序列,最后等待用户输入回车,程序正常退出。
3.3重命名
基于程序的功能,我将其命名为“堆排序算法的实现、优化与分析”
4.使用VSCode管理项目
4.1VSCode环境配置
我在软件商店中下载了VSCode,并搜索了MingGW进行相关环境配置
4.2在VSCode中编译运行

用VSCode打开进行编译运行即可,详情步骤不再赘述
5.代码版本管理
5.1Gitee仓库创建
在Gitee网站上创建账户,并建立项目库,配置git环境
5.2VSCode集成git
首先将本地gitee仓库初始化,复制下图链接,在桌面上右击鼠标打开Git Bash Here进行配置

然后通过VSCode打开相关文件夹,在文件夹中新建文件并进行如图git环境配置

即可关联远程仓库,将完整代码推送到远程仓库。

6.总结
本次堆排序代码实践,围绕一段传统堆排序代码,完成了从分析、诊断、优化到验证的全流程工作。通过排查,我发现了代码中存在的堆类型混淆、兼容性不足、数组越界等问题;通过优化,我修正了核心逻辑,解决了兼容性问题,规范了代码格式;通过实验验证,我确认了优化后代码的正确性与高效性。这段实践经历,让我不仅夯实了堆排序的理论基础,更提升了代码调试、优化与性能分析的实践能力,深刻体会到理论与实践结合的重要性。同时,我也认识到,在代码编写过程中,细节决定成败,一句错误的判断条件、一个不合理的边界顺序,都可能导致代码无法正常运行,因此,严谨细致的编程态度至关重要。
附录
344

被折叠的 条评论
为什么被折叠?



