怎样在 C 语言中实现堆排序?

news2024/9/22 19:35:05

C语言

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
📙C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

分割线

文章目录

  • C 语言中的堆排序实现
  • 一、堆排序的基本概念
  • 二、堆排序的基本原理
  • 三、堆排序的步骤
  • 四、C 语言实现堆排序
  • 五、代码解释
  • 六、时间复杂度和空间复杂度分析
  • 七、堆排序的优点和缺点
  • 八、应用场景
  • 九、与其他排序算法的比较
  • 十、总结

分割线


C 语言中的堆排序实现

一、堆排序的基本概念

堆排序(Heap Sort)是利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。

在堆排序中,我们通常使用最大堆来进行排序。最大堆的每个父节点的值都大于或等于其子节点的值。

二、堆排序的基本原理

堆排序的基本思想是:首先将待排序的数组构建成一个最大堆,然后将堆顶元素(最大值)与堆的最后一个元素交换位置,此时最大值就处于正确的位置(数组的末尾)。接下来,将剩余的元素重新调整为最大堆,再将堆顶元素与当前堆的最后一个未排序元素交换位置,重复这个过程,直到整个数组排序完成。

三、堆排序的步骤

  1. 构建最大堆

    • 从最后一个非叶子节点开始,依次向前调整每个节点及其子树,使其满足最大堆的性质。
  2. 交换堆顶和末尾元素

    • 将堆顶元素与堆的最后一个元素交换位置。
  3. 调整剩余堆为最大堆

    • 对除了已排序的末尾元素外的剩余元素重新调整为最大堆。
  4. 重复步骤 2 和 3,直到整个数组排序完成

四、C 语言实现堆排序

以下是一个用 C 语言实现堆排序的示例代码:

#include <stdio.h>

// 交换函数
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// 维护最大堆的性质
void maxHeapify(int arr[], int n, int i) {
    int largest = i;
    int l = 2 * i + 1;
    int 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) {
        swap(&arr[i], &arr[largest]);
        maxHeapify(arr, n, largest);
    }
}

// 构建最大堆
void buildMaxHeap(int arr[], int n) {
    for (int i = n / 2 - 1; i >= 0; i--)
        maxHeapify(arr, n, i);
}

// 堆排序函数
void heapSort(int arr[], int n) {
    buildMaxHeap(arr, n);

    for (int i = n - 1; i >= 0; i--) {
        swap(&arr[0], &arr[i]);
        maxHeapify(arr, i, 0);
    }
}

// 打印数组函数
void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

// 测试示例
int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);

    printf("排序前的数组为: ");
    printArray(arr, n);

    heapSort(arr, n);

    printf("排序后的数组为: ");
    printArray(arr, n);

    return 0;
}

在上述代码中,我们定义了以下几个函数:

  • swap 函数用于交换两个整数的位置。
  • maxHeapify 函数用于维护最大堆的性质。它接受一个数组、数组的长度和要调整的节点索引作为参数。通过比较节点与其子节点的值,将最大值交换到父节点的位置,并对可能受到影响的子树递归调用 maxHeapify 函数。
  • buildMaxHeap 函数用于构建最大堆。从最后一个非叶子节点开始,依次调用 maxHeapify 函数,确保整个数组满足最大堆的性质。
  • heapSort 函数是堆排序的核心函数。首先调用 buildMaxHeap 构建最大堆,然后通过不断交换堆顶元素和末尾元素,并对剩余元素重新调整为最大堆,实现排序。
  • printArray 函数用于打印数组的元素。

main 函数中,我们创建了一个测试数组,调用 heapSort 函数对其进行排序,并打印排序前后数组的元素。

五、代码解释

  1. swap 函数

    • 这个函数通过一个临时变量 temp 来实现两个整数的交换。
  2. maxHeapify 函数

    • 首先,确定当前节点 i 的左右子节点的索引 lr
    • 然后,找出 ilr 中值最大的节点索引,并存储在 largest 变量中。
    • 如果最大的值不在当前节点 i ,则将最大的值与当前节点交换位置,并对交换后的子树递归调用 maxHeapify 函数,以确保子树也满足最大堆的性质。
  3. buildMaxHeap 函数

    • 从最后一个非叶子节点开始,通过循环调用 maxHeapify 函数来构建最大堆。最后一个非叶子节点的索引为 n / 2 - 1
  4. heapSort 函数

    • 首先调用 buildMaxHeap 函数构建最大堆。
    • 然后通过一个循环,每次将堆顶元素与末尾未排序的元素交换位置,并对剩余的元素调用 maxHeapify 函数重新调整为最大堆。

六、时间复杂度和空间复杂度分析

  1. 时间复杂度

    • 堆排序的时间复杂度为 O(nlogn) 。其中,构建最大堆的时间复杂度为 O(n) ,每次调整最大堆的时间复杂度为 O(logn) ,在排序过程中需要进行 n - 1 次调整,所以总的时间复杂度为 O(nlogn)
  2. 空间复杂度

    • 堆排序的空间复杂度为 O(1) 。因为整个排序过程只在原数组上进行操作,没有额外的空间开销。

七、堆排序的优点和缺点

  1. 优点

    • 堆排序在最坏情况下的时间复杂度仍然为 O(nlogn) ,性能较为稳定。
    • 是一种原地排序算法,不需要额外的存储空间,空间复杂度低。
  2. 缺点

    • 堆排序的性能在实际应用中通常比快速排序稍逊一筹。
    • 构建堆的过程相对较为复杂,理解和实现起来有一定难度。

八、应用场景

堆排序适用于对时间复杂度要求较高,且对空间复杂度有限制的场景,例如在嵌入式系统或资源受限的环境中。

九、与其他排序算法的比较

  1. 与冒泡排序相比

    • 冒泡排序的时间复杂度为 O(n^2) ,而堆排序的时间复杂度为 O(nlogn) ,在大多数情况下,堆排序的性能优于冒泡排序。
  2. 与快速排序相比

    • 快速排序在平均情况下的性能非常出色,时间复杂度也为 O(nlogn) 。但在最坏情况下,快速排序的时间复杂度可能退化为 O(n^2) ,而堆排序在最坏情况下仍然保持 O(nlogn) 的时间复杂度。
  3. 与归并排序相比

    • 归并排序的时间复杂度和堆排序相同,均为 O(nlogn) ,但归并排序需要额外的辅助空间,空间复杂度为 O(n) ,而堆排序是原地排序,空间复杂度为 O(1)

十、总结

堆排序是一种高效的排序算法,通过构建最大堆和不断交换堆顶元素与末尾元素来实现排序。虽然在实际应用中可能不如快速排序等算法常用,但在特定的场景下,如对空间要求严格的环境中,具有一定的优势。理解和掌握堆排序的原理和实现对于深入理解算法和数据结构的知识体系具有重要意义。


分割线

🎉相关推荐

  • 📙C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。
  • 🍅博客首页-关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📙CSDN专栏-C语言修炼
  • 📙技术社区-墨松科技

分割线



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

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

相关文章

小程序-设置环境变量

在实际开发中&#xff0c;不同的开发环境&#xff0c;调用的接口地址是不一样的 例如&#xff1a;开发环境需要调用开发版的接口地址&#xff0c;生产环境需要正式版的接口地址 这时候&#xff0c;我们就可以使用小程序提供了 wx.getAccountInfoSync() 接口&#xff0c;用来获取…

分享 | 一文简述模糊测试智能体技术实践

近日&#xff0c;华为2012实验室中央软件院旗下的欧拉多咖创新团队成功举办了【欧拉多咖 — 操作系统研讨会】。本次研讨会以“系统安全AI&#xff1f;”为主题&#xff0c;探讨了大模型技术如何推动基础软件迈向大规模算力时代&#xff0c;并详细讨论了在这一过程中系统软件所…

论文 | LEAST-TO-MOST PROMPTING ENABLES COMPLEXREASONING IN LARGE LANGUAGE MODELS

论文主题&#xff1a; 这篇论文提出了“从简单到复杂提示”&#xff08;Least-to-Most Prompting&#xff09;这一新的提示策略&#xff0c;旨在解决大语言模型在解决比提示示例更复杂的问题时表现不佳的难题。 核心思想&#xff1a; 将复杂问题分解成一系列更简单的子问题。按…

Verilog基础:操作数的位选(bit-select)和域选(part select)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 位选 位选(bit-select)用于选择一个向量(vector)的某位&#xff0c;可以是线网大类(net)&#xff0c;也可以是变量大类(variable)中的reg、integer和time&#xf…

Redis 主从复制,哨兵与集群

目录 一.redis主从复制 1.redis 主从复制架构 2.主从复制特点 3.主从复制的基本原理 4.命令行配置 5.实现主从复制 6.删除主从复制 7.主从复制故障恢复 8.主从复制完整过程 9.主从同步优化配置 二.哨兵模式&#xff08;Sentinel&#xff09; 1.主要组件和概念 2.哨…

半小时获得一张ESG入门证书【详细中英文笔记一】

前些日子&#xff0c;有朋友转发了一则小红书的笔记给我&#xff0c; 标题是《半小时获CFI官方高颜值免费证书 ESG认证》。这对考证狂魔的我来说&#xff0c;必然不能错过啊&#xff0c;有免费的羊毛不薅白不薅。 ESG课程的 CFI 官方网址戳这里&#xff1a;CFI 于是信心满满的…

Electron运行报错:Error Cannot find module ‘node_moduleselectroncli.js‘

Electron运行报错&#xff1a;Error: Cannot find module ‘node_modules\electron\cli.js’ 顾名思义&#xff0c;命令行执行Electron .时候&#xff0c;会优先从项目目录查找对应依赖&#xff0c;如果是报错显示是找不到项目目录下的依赖&#xff0c;我们可以从安装在全局的…

轮转数组(时间复杂度不同的三种思路)

&#xff08;来源&#xff1a;LeetCode&#xff09; 题目 分析 其实一次轮转就是将最后一个数据放到最前面&#xff0c;其他数据整体向后移动一位。k为几就重复这个行为几次。 思路1 我们应该很快能想到最直接的一种思路。while(k--)……循环内完成两件事&#xff0c;保存最…

【C++】函数重载详解

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

Python面试全攻略:基础知识、特性、算法与实战解析

随着Python的普及&#xff0c;越来越多的人开始学习Python并尝试在面试中展示自己的技能。在这篇文章中&#xff0c;我们将探讨Python面试需要注意的问题以及一些经典的Python算法。 一、Python面试需要注意的问题 基础知识 在Python面试中&#xff0c;基础知识是非常重要的。…

开源浪潮:助力未来科技的飞速发展

文章目录 开源项目有哪些机遇与挑战&#xff1f;开源项目的发展趋势发展现状开源社区的活跃度 我是如何参与开源项目的经验分享选择开源项目贡献代码 开源项目的挑战开源项目面临的挑战 开源项目有哪些机遇与挑战&#xff1f; 随着全球经济和科技环境的快速变化&#xff0c;开源…

设计模式 - 最简单最有趣的方式讲述

别名《我替你看Head First设计模式》 本文以故事的形式带你从0了解设计模式&#xff0c;在其中你仅仅是一名刚入职的实习生&#xff0c;在项目中摸爬滚打。&#xff08;以没有一行真正代码的形式&#xff0c;让你无压力趣味学习&#xff09; 设计模式 策略模式观察者模式装饰者…

【简历】重庆某一本大学:JAVA简历指导,中厂通过率较低

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份重庆某一本大学Java同学的简历。那么因为学校是一个一本的学校&#xff0c;就先要确定就业层次在中厂或者大厂&#xff0c;但是…

Zed 编辑器发布了原生 Linux 版本

由 Rust 编写、GPU 加速的 Zed 文本编辑器终于提供了正式的 Linux 原生版本&#xff01;在过去的几个月里&#xff0c;Zed 的 Linux 支持取得了长足的进步&#xff0c;现在已经进入了更正式的阶段。 今天&#xff0c;这款由前 Atom 开发人员创建的现代开源代码编辑器现在在 Li…

算法的几种常见形式

算法&#xff08;Algorithm&#xff09; 算法&#xff08;Algorithm&#xff09;是指解决问题或完成任务的一系列明确的步骤或规则。在计算机科学中&#xff0c;算法是程序的核心部分&#xff0c;它定义了如何执行特定的任务或解决特定的问题。算法可以用多种方式来表示和实现…

如何在小红书上面有效地种草?

文末领取小红书电商开店运营教程&#xff01; 小红书是一个以内容分享为主的社交平台&#xff0c;大家喜欢在这里分享自己的生活体验和心得&#xff0c;其中就包括各种产品的使用感受。 那么我们要想在小红书上有效地种草&#xff0c;首先就需要了解并掌握小红书的种草文化。 …

JavaScript(8)——函数

函数 function,是被设计执行特定任务的代码块。 函数可以把具有相同或相似逻辑的代码包裹起来&#xff0c;通过函数调用执行这些代码&#xff0c;这么做的优势有利于精简代码方便复用。类似于alert(),prompt()和console.log()&#xff0c;这些都是js函数&#xff0c;不过已经…

C++学习书籍推荐

第一本&#xff1a;C Primer CPrimer&#xff1a;主要讲解语法&#xff0c;经典的语法书籍&#xff0c;前后中期都可以看&#xff0c;前期如果⾃学看可能会有点晦涩 难懂&#xff0c;能看懂多少看懂多少&#xff0c;就当预习&#xff0c;中后期作为语法字典&#xff0c;⾮常好⽤…

Android11 SplashScreen 的显示和退出流程

应用的启动到显示到屏幕是需要一定的时间的&#xff0c;为了提升用户的体验&#xff0c;google加入了启动窗口&#xff0c;也就是SplashScreen SplashScreen显示流程 在应用的启动过程中&#xff0c;会调用到ActivityStarter的startActivityInner方法&#xff0c;具体可参考&a…

STM32HAL库+ESP8266+cJSON+微信小程序_连接华为云物联网平台

STM32HAL库ESP8266cJSON微信小程序_连接华为云物联网平台 实验使用资源&#xff1a;正点原子F407 USART1&#xff1a;PA9P、A10&#xff08;串口打印调试&#xff09; USART3&#xff1a;PB10、PB11&#xff08;WiFi模块&#xff09; DHT11&#xff1a;PG9&#xff08;采集数据…