堆排序算法详解与C代码实现

堆排序算法详解与C代码实现

  • 一、堆排序的基本概念
  • 二、堆排序的主要过程
    • 建堆
    • 堆调整
  • 三、堆排序算法的特点
  • 四、堆排序的C代码实现

在众多的排序算法中,堆排序以其独特的性质和高效的性能脱颖而出。堆排序算法利用堆这种数据结构所设计的一种排序算法,它是选择排序的一种。可以利用数组来模拟堆的结构以进行排序。堆排序可以分为两个主要的过程:建堆和堆调整。

在这里插入图片描述

一、堆排序的基本概念

堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种树形选择排序,是对直接选择排序的有效改进。堆的定义如下:具有n个元素的序列(h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆。在这里只讨论满足hi>=h2i且hi>=2i+1的堆称为大根堆,亦称最大堆或最大完全二叉树。堆排序是一种树形选择排序方法,是对直接选择排序的有效改进。

堆的定义如下:具有n个元素的序列(h1,h2,…,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1) (i=1,2,…,n/2)时称之为堆。在这里只讨论满足hi>=h2i且hi>=2i+1的堆称为大根堆,亦称最大堆或最大完全二叉树。堆中最大元素值总是在堆的根节点上。堆中任一非终端节点的数据值均不小于其左子节点和右子节点的值。堆排序就是利用堆进行排序的方法。它的基本思想是:将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就为最大值),然后将剩余的n-1个序列重新构造成一个堆,这样会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。

二、堆排序的主要过程

堆排序包括两个主要的过程:建堆和堆调整。

建堆

建堆,就是将一个无序的序列调整成为一个大顶堆(或小顶堆)。在堆中,父节点的值总是大于或等于(或小于或等于)它的子节点的值。在堆排序算法中,我们通常采用大顶堆。

建堆的过程,是从最后一个非叶子节点开始,将其调整成为堆。然后向前依次调整每一个非叶子节点,直到整个序列都成为堆。具体步骤如下:

(1)将n个待排序的元素构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。

(2)将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个序列重新构造成一个堆,这样会得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。

建堆的时间复杂度是O(n)。

堆调整

堆调整的过程,其实就是删除堆顶元素,然后将剩余元素重新调整成为堆的过程。具体步骤如下:

(1)删除堆顶元素。

(2)将堆尾元素放到堆顶。

(3)从堆顶开始向下调整堆。具体调整方法是从堆顶开始,将其与左子节点和右子节点比较,如果比子节点小,则与子节点中较大的一个交换。然后继续向下调整,直到叶子节点或者比子节点大为止。

堆调整的时间复杂度是O(logn)。

三、堆排序算法的特点

堆排序算法的主要特点如下:

堆排序是不稳定的排序方法。
堆排序的时间复杂度为O(nlogn)。
堆排序的空间复杂度为O(1)。

四、堆排序的C代码实现

以下是堆排序的C代码实现:

#include <stdio.h>  void swap(int* a, int* b) {  int t = *a;  *a = *b;  *b = t;  
}  void heapify(int arr[], int n, int i) {  int largest = i;  // Initialize largest as root  int left = 2 * i + 1;  // left = 2*i + 1  int right = 2 * i + 2;  // right = 2*i + 2  //如果左子节点比根节点大,则更新最大值
if (left < n && arr[left] > arr[largest])
largest = left;// 如果右子节点比目前已知的最大值还大,则更新最大值  
if (right < n && arr[right] > arr[largest])  largest = right;  // 如果最大值不是根节点  
if (largest != i) {  swap(&arr[i], &arr[largest]);  // 递归地调整受影响的子堆  heapify(arr, n, largest);  
}
}void heapSort(int arr[], int n) {
// 建堆
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);// 一个个从堆顶取出元素  
for (int i = n - 1; i >= 0; i--) {  // 将当前最大的元素arr[0]与arr[i]交换  swap(&arr[0], &arr[i]);  // 调整剩余元素,使其重新成为堆  heapify(arr, i, 0);  
}
}void printArray(int arr[], int n) {
for (int i = 0; i < n; ++i)
printf("%d ", arr[i]);
printf("\n");
}int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);heapSort(arr, n);  printf("Sorted array is \n");  
printArray(arr, n);
}

这段代码首先定义了一个swap函数用于交换两个元素的值,然后定义了heapify函数用于调整堆。在heapSort函数中,首先通过heapify函数将数组构造成一个大顶堆,然后依次将堆顶元素与末尾元素交换,并重新调整堆,直到整个数组有序。

堆排序的时间复杂度是O(nlogn),其中建堆的时间复杂度是O(n),堆调整的时间复杂度是O(logn),总共需要进行n次堆调整。因此,堆排序是一种高效的排序算法,适用于处理大量数据。

需要注意的是,堆排序是一种不稳定的排序算法,即相同元素的相对顺序在排序过程中可能会发生改变。如果需要稳定的排序算法,可以考虑使用归并排序或冒泡排序等算法。

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

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

相关文章

Advisor 被重复代理问题排查

问题场景 项目中存在多个 AbstractAdvisorAutoProxyCreator 且其持有的 Advisor Bean 重复 问题复现 相关代码 ResponseBodyRequiresPermissions(PermissionConstant.****)GetMapping(value "/query****.json", name "")public List<***> query…

新穗青少年开展“小小公民科学家”科考活动探索生物多样性

为帮助“新穗”青少年了解本土文化&#xff0c;提升个人知识面和动手能力&#xff0c;贯彻落实《未成年人保护法》《家庭教育促进法》《广东省生态环境教育条例》等有关文件精神&#xff0c;3月24日&#xff0c;天河区绿日同学公益服务促进会联合华南农业大学农潮工作室、广州城…

docker logs 查找日志常用命令

docker logs 是什么 docker logs 是 Docker 命令行工具提供的一个命令&#xff0c;用于查看容器的日志输出。它可以显示容器在运行过程中生成的标准输出&#xff08;stdout&#xff09;和标准错误输出&#xff08;stderr&#xff09;&#xff0c;帮助用户诊断容器的行为和排查…

阿里通义千问Qwen1.5开源MoE模型

介绍 2024年3月28日&#xff0c;阿里团队推出了Qwen系列的首个MoE模型&#xff0c;Qwen1.5-MoE-A2.7B。它仅拥有27亿个激活参数&#xff0c;但其性能却能与当前最先进的70亿参数模型&#xff0c;如Mistral 7B和Qwen1.5-7B相媲美。相较于包含65亿个Non-Embedding参数的Qwen1.5-…

element-ui/view-ui表格的合并行和列的多种方法(超级详细)

vue的这两个组件库的表格的行和列的写法是一样的&#xff0c;都是通过span-method方法可以实现的&#xff1b;下面我们就以view ui的表格组件为例&#xff1b; 该方法参数为 4 个对象&#xff1a; row: 当前行column: 当前列rowIndex: 当前行索引columnIndex: 当前列索引 该…

linux 环境安装配置

安装java17 1.下载安装包 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 2.解压到自定义目录/usr/local/java mkdir /usr/local/java tar zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java 3.配置环境变量 echo export PATH$PATH:/…

神策数据参与制定首份 SDK 网络安全国家标准

国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2023 年第 13 号&#xff09;&#xff0c;全国信息安全标准化技术委员会归口的 3 项国家标准正式发布。其中&#xff0c;首份 SDK 国家标准《信息安全技术 移动互联网应用程序&#xff0…

HCIE考试第二题:业务容器镜像制作

业务容器镜像制作做题目与题步骤如下 题目 解题步骤 业务容器镜像制作 2.1创建VPC 登录总部SC 创建一个VPC 网段环境有说,租户CCE子网就是 都保持默认,加个描述就好了 创建成功 2.2对等连接Peering 其实就是当前主机连http源那个资源服务器用的。 创建成功 【考试联系考官…

2024年2月游戏手柄线上电商(京东天猫淘宝)综合热销排行榜

鲸参谋监测的线上电商&#xff08;京东天猫淘宝&#xff09;游戏手柄品牌销售数据已出炉&#xff01;2月游戏手柄销售数据呈现出强劲的增长势头。 根据鲸参谋数据显示&#xff0c;今年2月游戏手柄月销售量累计约43万件&#xff0c;同比去年上涨了78%&#xff1b;销售额累计达1…

简单线程池的实现

线程池的代码可以写的很复杂&#xff0c;这里就稍微简单一些 首先来看一下线程池的原则&#xff0c;下面的大框是服务器&#xff0c;而在服务器中维护一个任务队列。 然后在server中预先创建一批线程&#xff0c;这批线程和任务队列合在一起只用向外界提供一个入队列的接口。 …

直流马达驱动芯片D6289ADA介绍

应用领域 适用于智能断路器&#xff08;家用或工业智能空开&#xff09;、新能源汽车充电枪锁、电动玩具、电磁门锁、自动阀门等的直流电机驱动。 功能介绍 D6289ADA是一款直流马达驱动芯片&#xff0c;它有两个逻辑输入端子用来控制电机前进、后退及制动。该电路具有良好的抗干…

[每日一氵] 将服务器的某个端口映射为另一台服务器的ssh连接地址

拓扑结构图&#xff0c;小火龙如何通过服务器A的某个端口ssh连接到服务器B呢? ssh连接准备 首先开启服务器B的ssh连接&#xff0c;若显示: ssh xxlocalhostssh: connect to host localhost port 22: Connection refused也许是ssh没安装 sudo apt-get install openssh-ser…