堆排序(C语言版)

一.堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:
1. 建堆
升序:建大堆
降序:建小堆
2. 利用堆删除思想来进行排序

1.1.利用上下调整法实现堆排序

第一步:建堆

好了,每次建堆都要问自己下,要建的是什么堆?大堆还是小堆呢?

我们这里就一一来实现,先建大堆

void Print(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}
void Swap(int* p1, int* p2)
{int* tmp = *p1;* p1=*p2;*p2 = tmp;
}
void Adjustup(int* arr2, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr2[child]>arr2[parent])//注意我们是建的大堆{Swap(&arr2[child], &arr2[parent]);//传地址才能改变值child = parent;parent = (child - 1) / 2;}else{break;}}
}
void Heapsort(int* arr, int n)
{//建立堆//问题是:你是建大堆还是小堆?//我们这里要建大堆for (int i = 1; i < n; i++){Adjustup(arr, i);//利用向上调整法}Print(arr,n);
}

如果你实现过堆的代码相信上面的代码对你来说绝对小菜一碟

由于我们直接调用了打印函数,那么我们来看看结果吧。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Print(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}
void Swap(int* p1, int* p2)
{int* tmp = *p1;* p1=*p2;*p2 = tmp;
}
void Adjustup(int* arr2, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr2[child]>arr2[parent])//注意我们是建的大堆{Swap(&arr2[child], &arr2[parent]);//传地址才能改变值child = parent;parent = (child - 1) / 2;}else{break;}}
}
void Heapsort(int* arr, int n)
{//建立堆//问题是:你是建大堆还是小堆?//我们这里要建大堆for (int i = 1; i < n; i++){Adjustup(arr, i);//利用向上调整法}Print(arr,n);
}
int main()
{int arr[] = { 4,6,2,1,5,8,2,9 };int sz = sizeof(arr) / sizeof(int);Heapsort(arr, sz);return 0;
}

结果:

这个是不是就满足了大堆

第二步:如何实现排序呢?(别看上面是从大到小排好的,这只是一个巧合,我们要学会正确的排序法)

如果你对此不清楚,那么我要开始表演了。

如果你想,我们是大堆,这说明最大的数即是堆顶,如果我交换数组首尾位置,然后这是不是不再是一颗完全二叉树了,那么如果我再通过向下调整法来排好,重复操作,是不是就会得到一个从小到大的数组,那么不就排好序了,想到这,相信你肯定联想到了堆的删除操作,下面就让我们利用堆的删除来实现它吧!


void Swap(int* p1, int* p2)
{int* tmp = *p1;* p1=*p2;*p2 = tmp;
}
void Adjustdown(int* arr3, int n, int parent)
{int child = parent * 2 + 1;//假设左孩子大//注意我们建的是大堆while (child < n){if ((child + 1) < n && (arr3[child] < arr3[child + 1])){child++;}if (arr3[parent] < arr3[child]){Swap(&arr3[parent], &arr3[child]);//交换父子位置parent = child;child = parent * 2 + 1;}else{break;}}
}//堆建好了,现在实现第二步:堆删除
int end = n - 1;
while (end > 0)
{//堆删除分以下几步://第一步:首尾元素互换Swap(&arr[0], &arr[end]);//第二步:向下调整法调整树根Adjustdown(arr, end, 0);//第三步:删除堆尾end--;
}

这对于学过实现堆的你来说依然so easy。

那么就让我们整体检查代码的正确性:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Print(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}
void Swap(int* p1, int* p2)
{int* tmp = *p1;* p1=*p2;*p2 = tmp;
}
void Adjustup(int* arr2, int child)
{int parent = (child - 1) / 2;while (child > 0){if (arr2[child]>arr2[parent])//注意我们是建的大堆{Swap(&arr2[child], &arr2[parent]);//传地址才能改变值child = parent;parent = (child - 1) / 2;}else{break;}}
}
void Adjustdown(int* arr3, int n, int parent)
{int child = parent * 2 + 1;//假设左孩子大//注意我们建的是大堆while (child < n){if ((child + 1) < n && (arr3[child] < arr3[child + 1])){child++;}if (arr3[parent] < arr3[child]){Swap(&arr3[parent], &arr3[child]);//交换父子位置parent = child;child = parent * 2 + 1;}else{break;}}
}
void Heapsort(int* arr, int n)
{//建立堆//问题是:你是建大堆还是小堆?//我们这里要建大堆for (int i = 1; i < n; i++){Adjustup(arr, i);//利用向上调整法}Print(arr,n);//堆建好了,现在实现第二步:堆删除int end = n - 1;while (end > 0){//堆删除分以下几步://第一步:首尾元素互换Swap(&arr[0], &arr[end]);//第二步:向下调整法调整树根Adjustdown(arr, end, 0);//第三步:删除堆尾end--;}Print(arr, n);
}
int main()
{int arr[] = { 4,6,2,1,5,8,2,9 };int sz = sizeof(arr) / sizeof(int);Heapsort(arr, sz);return 0;
}

结果:

如果你是要从大到小排序,操作如下:

建小堆-》堆的尾删

整体而言有三处改动:

1.在void Adjustup(int* arr2, int child)函数中这个语句要改变符号,因为是建小堆了。
        if (arr2[child]>arr2[parent])//
2.在void Adjustdown(int* arr3, int n, int parent)这个函数中这两处符号也要改变,原因是因为你现在是小堆,向下调整法肯定要调整
        if (arr3[child] < arr3[child + 1]))
        if (arr3[parent] < arr3[child])
 

整体如下:

//表示原来的语句//arr2[child]>arr2[parent]
arr2[child]<arr2[parent]//if ((child + 1) < n && (arr3[child] < arr3[child + 1]))
if ((child + 1) < n && (arr3[child] > arr3[child + 1]))//if (arr3[parent] < arr3[child])
if (arr3[parent] > arr3[child])

改完之后结果如下:

现在我们就要对这个算法进行分析:

时间复杂度:建堆为O(NlogN)+选数O(N-1logN)

得出结果:O(NlogN)(非常牛逼的算法)

1.2.只利用向下调整法实现堆排序

大家看上面的代码是不是感觉一个排序要写这么麻烦好不方便啊,是的,我们其实可以只通过一个向下调整就可以实现堆排序,下面看看我的表演吧!

步骤还是和上面一样,其实就改变了建堆的过程,我们现在是通过向下调整法建堆。

看代码:

for (int i = ; i ; i)
{Adjustdown(arr,,);
}

我们就是要把上面的空缺填好,那么该如何写呢?

我要告诉你一个概念:向下调整建堆是从第一个非叶子节点开始调整,我们肯定要调整到0

所以我们可以这样写:

for (int i = (n - 1 - 1) / 2; i >= 0; i--)
{Adjustdown(arr,n,i);
}

其他部分不用改变,所以整体代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Print(int* arr, int n)
{for (int i = 0; i < n; i++){printf("%d ", arr[i]);}printf("\n");
}
void Swap(int* p1, int* p2)
{int* tmp = *p1;* p1=*p2;*p2 = tmp;
}
void Adjustdown(int* arr3, int n, int parent)
{int child = parent * 2 + 1;//假设左孩子大//注意我们建的是大堆while (child < n){if ((child + 1) < n && (arr3[child] < arr3[child + 1])){child++;}if (arr3[parent] < arr3[child]){Swap(&arr3[parent], &arr3[child]);//交换父子位置parent = child;child = parent * 2 + 1;}else{break;}}
}
void Heapsort(int* arr, int n)
{for (int i = (n - 1 - 1) / 2; i >= 0; i--){Adjustdown(arr,n,i);}Print(arr, n);//堆建好了,现在实现第二步:堆删除int end = n - 1;while (end > 0){//堆删除分以下几步://第一步:首尾元素互换Swap(&arr[0], &arr[end]);//第二步:向下调整法调整树根Adjustdown(arr, end, 0);//第三步:删除堆尾end--;}Print(arr, n);
}
int main()
{int arr[] = { 4,6,2,1,5,8,2,9 };int sz = sizeof(arr) / sizeof(int);Heapsort(arr, sz);return 0;
}

结果:

来我们该讨论该算法时间复杂度情况了

建堆O(N)+选数O(NlogN)

时间复杂度:O(N*logN)

注意:该写法不仅简单(比上面那种),而且效率也比上面的高。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ArkTS基本概念装饰器

目录 ArkTS基本概念 装饰器汇总 ArkTS基本概念 ArkTS是HarmonyOS的主力应用开发语言。 它在TypeScript&#xff08;简称TS&#xff09;的基础上&#xff0c;匹配ArkUI框架&#xff0c;扩展了声明式UI、状态管理等相应的能力&#xff0c;让开发者以更简洁、更自然的方式开发跨…

cocos creator + vscode debug

安装插件 安装插件&#xff1a;JavaScript Debugger 配置 7456 为本地cocos creator的启动端口 启动debug调试 选择对应的启动方式

低成本TB级数据库技术选型之思考两三点

一、背景 前段时间在搞毕业论文的选题&#xff0c;最头疼的就是大量的文献检索和阅读&#xff0c;从研究的角度上我们可以将文献分为四类&#xff1a; 理论文献&#xff1a;为研究提供理论的框架和基础的文献。这些文献可能并不会和所做的研究直接相关&#xff0c;甚至由于理…

叫板GPT-4的Gemini,我做了一个聊天网页,可图片输入,附教程

先看效果&#xff1a; 简介 Gemini 是谷歌研发的最新一代大语言模型&#xff0c;目前有三个版本&#xff0c;被称为中杯、大杯、超大杯&#xff0c;Gemini Ultra 号称可与GPT-4一较高低&#xff1a; Gemini Nano(预览访问) 为设备端体验而构建的最高效模型,支持离线使用场景。…

基于PI控制的PMSM永磁同步电机控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 PMSM数学模型 4.2 矢量控制策略 4.3 PI控制器设计 4.4 控制系统实现 5.完整工程文件 1.课题概述 基于PI控制的PMSM永磁同步电机控制系统simulink建模与仿真。其中&#xff0c;基于PI&#xff08;…

查看ios app运行日志

摘要 本文介绍了一款名为克魔助手的iOS应用日志查看工具&#xff0c;该工具可以方便地查看iPhone设备上应用和系统运行时的实时日志和奔溃日志。同时还提供了奔溃日志分析查看模块&#xff0c;可以对苹果奔溃日志进行符号化、格式化和分析&#xff0c;极大地简化了开发者的调试…

极值和平均值-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第22讲。 极值和平均值&…

java设计模式实战【策略模式+观察者模式+命令模式+组合模式,混合模式在支付系统中的应用】

引言 在代码开发的世界里&#xff0c;理论知识的重要性毋庸置疑&#xff0c;但实战经验往往才是知识的真正试金石。正所谓&#xff0c;“读万卷书不如行万里路”&#xff0c;理论的学习需要通过实践来验证和深化。设计模式作为软件开发中的重要理论&#xff0c;其真正的价值在…

【心得】PHP反序列化高级利用(phar|session)个人笔记

目录 ①phar反序列化 ②session反序列化 ①phar反序列化 phar 认为是java的jar包 calc.exe phar能干什么 多个php合并为独立压缩包&#xff0c;不解压就能执行里面的php文件&#xff0c;支持web服务器和命令行 phar协议 phar://xxx.phar $phar->setmetadata($h); m…

计算机视觉与自然语言处理(Open AI)

1.语音识别技术 语音识别是将语音转换为文本的技术&#xff0c; 是自然语言处理的一个分支。通过特征的提取、模式的匹配将语音信号变为文本或命令&#xff0c;以实现机器识别和理解语音。 按照应用场景的不同&#xff0c;可以大致分为三类&#xff1b; • 电信级系统应用&…

动画墙纸:将视频、网页、游戏、模拟器变成windows墙纸——Lively Wallpaper

文章目录 前言下载github地址&#xff1a;网盘 关于VideoWebpagesYoutube和流媒体ShadersGIFs游戏和应用程序& more:Performance:多监视器支持&#xff1a;完结 前言 Lively Wallpaper是一款开源的视频壁纸桌面软件&#xff0c;类似 Wallpaper Engine&#xff0c;兼容 Wal…

echarts手动触发气泡的显示和隐藏

点击echarts图表后将点击的那个进行突出显示 <template><div id"demo"> </div><el-button type"primary" click"set">设置</el-button><el-button type"primary" click"cancel">取消&…

ubuntu20部署Bringing-Old-Photos-Back-to-Life

环境准备&#xff1a; ubuntu20.04 Python 3.8.10 首先将微软的「Bringing-Old-Photos-Back-to-Life」库 clone 到本地&#xff1a; git clone https://github.com/microsoft/Bringing-Old-Photos-Back-to-Life.git cd Face_Enhancement/models/networks/ git clone https:/…

API 开放平台项目(已整理,已废弃)

项目大纲 前端 React 18Ant Design Pro 5.x 脚手架Ant Design & Procomponents 组件库Umi 4 前端框架OpenAPI 前端代码生成 后端 Java Spring BootMySQL 数据库MyBatis-Plus 及 MyBatis X 自动生成API 签名认证&#xff08;Http 调用&#xff09;Spring Boot Starter&#…

Langchain访问OpenAI ChatGPT API Account deactivated的另类方法,访问跳板机API

笔者曾经写过 ChatGPT OpenAI API请求限制 尝试解决 Account deactivated. Please contact us through our help center at help.openai.com if you need assistance. 结果如何&#xff1f; 没有啥用。目前发现一条曲线救国的方案。 1. 在官方 openai 库中使用 此处为最新Op…

Jupyter Notebook的10个常用扩展介绍

Jupyter Notebook&#xff08;前身为IPython Notebook&#xff09;是一种开源的交互式计算和数据可视化的工具&#xff0c;广泛用于数据科学、机器学习、科学研究和教育等领域。它提供了一个基于Web的界面&#xff0c;允许用户创建和共享文档&#xff0c;这些文档包含实时代码、…

『番外篇九』SwiftUI 实战:打造一款“五脏俱全”的网络图片显示 App(上)

概览 俗话说得好:“读书破万卷,下笔如有神”。不过如果把这句话放到编程的学习上可就不那么贴切了。 要想熟练掌握一门编程语言,光看书是绝对不够的。我们还需尽可能的多撸码、早撸码,撸到无路可退、海枯石烂才有可能一窥门径。 在本篇和续篇博文中,我们将和小伙伴们一起…

Linux 内核学习笔记: hlist 的理解

前言 最近阅读 Linux 内核时&#xff0c;遇到了 hlist&#xff0c;这个 hlist 用起来像是普通的链表&#xff0c;但是为何使用 hlist&#xff0c;hlist 是怎么工作的&#xff1f; 相关代码 hlist_add_head(&clk->clks_node, &core->clks); /*** clk_core_link_…

华为鸿蒙运行Hello World

前言&#xff1a; 从11月中旬开始通过B站帝心接触鸿蒙&#xff0c;至今一个半月左右不到&#xff0c;从小白到入坑&#xff0c;再到看官网案例&#xff0c;分析案例&#xff0c;了解技术点&#xff0c;还需要理清思路&#xff0c;再写博客&#xff0c;在决定写 &#xff1c;Har…

DragonEnglish:COCA20000+单词+释义

去年的时候接触到了 COCA20000 单词&#xff0c;对这种给单词特定顺序的方式蛮感兴趣的。因为我当时接触的版本只有单词或者单词释义的版本&#xff0c;所以我直接通过各种方式给它搭配了音标例句发音&#xff0c;然后每100个切割成1份&#xff0c;分成了 202 个文件来学习&…