高级排序算法(二):归并排序与堆排序详解

引言

在上一章中,我们探讨了高效的快速排序及其分治思想。这一次,我们将继续探索两种同样重要的排序算法:归并排序(Merge Sort)堆排序(Heap Sort)
它们与快速排序一样,都是O(n log n)时间复杂度的排序算法,但实现方式和适用场景却各有不同。归并排序在稳定性和分布式场景中表现优异,而堆排序则在内存有限的情况下表现突出。

接下来,我们将一起深入剖析这两种排序算法的原理、实现与应用。


一、归并排序(Merge Sort)

1.1 算法思想

归并排序是典型的分治法应用,采用“分而治之”的思想,递归地将数组分成两部分,分别排序后再合并。

1.2 算法过程
  1. 分解:将数组从中间分成两部分,直到每部分只有一个元素(显然是有序的)。
  2. 合并:将两个有序的子数组合并成一个有序数组。
  3. 递归:对每个子数组重复上述过程。
1.3 C语言实现
​
#include <stdio.h>
#include <stdlib.h>// 合并两个有序子数组
void merge(int arr[], int left, int mid, int right) {int n1 = mid - left + 1;  // 左子数组的大小int n2 = right - mid;     // 右子数组的大小// 创建临时数组int* L = (int*)malloc(n1 * sizeof(int));int* R = (int*)malloc(n2 * sizeof(int));// 复制数据到临时数组for (int i = 0; i < n1; i++) L[i] = arr[left + i];for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];// 合并临时数组到原数组int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k++] = L[i++];} else {arr[k++] = R[j++];}}// 复制剩余元素while (i < n1) arr[k++] = L[i++];while (j < n2) arr[k++] = R[j++];// 释放临时数组free(L);free(R);
}// 归并排序
void mergeSort(int arr[], int left, int right) {if (left < right) {int mid = left + (right - left) / 2;  // 防止溢出mergeSort(arr, left, mid);           // 排序左半部分mergeSort(arr, mid + 1, right);      // 排序右半部分merge(arr, left, mid, right);        // 合并两部分}
}int main() {int arr[] = {38, 27, 43, 3, 9, 82, 10};int n = sizeof(arr) / sizeof(arr[0]);mergeSort(arr, 0, n - 1);printf("排序后的数组: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}return 0;
}​
1.4 时间和空间复杂度
  • 时间复杂度
    • 每次分解需要log n层。
    • 每次合并需要O(n)时间。
    • 总体时间复杂度为O(n log n)
  • 空间复杂度
    • 由于需要额外的临时数组,空间复杂度为O(n)
1.5 优点与缺点
  • 优点
    • 时间复杂度始终为O(n log n),无最坏情况。
    • 稳定排序,适用于需要保持顺序的场景。
  • 缺点
    • 需要额外的存储空间,空间复杂度较高。

二、堆排序(Heap Sort)

2.1 算法思想

堆排序是基于堆数据结构的排序算法,通过构建最大堆最小堆实现排序。

  • 最大堆:堆顶(根节点)是堆中最大的元素。
  • 最小堆:堆顶(根节点)是堆中最小的元素。

堆排序的过程可以分为两个步骤:

  1. 构建堆:将无序数组调整为一个最大堆。
  2. 排序:依次将堆顶元素(最大值)与最后一个元素交换,并调整堆。
2.2 C语言实现

构建堆的核心:向下调整(Heapify)

​
void heapify(int arr[], int n, int i) {int largest = i;           // 假设当前节点是最大的int left = 2 * i + 1;      // 左子节点int 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) {int temp = arr[i];arr[i] = arr[largest];arr[largest] = temp;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--) {// 将当前堆顶元素(最大值)移到数组末尾int temp = arr[0];arr[0] = arr[i];arr[i] = temp;// 调整剩余部分,重新构建堆heapify(arr, i, 0);}
}int main() {int arr[] = {12, 11, 13, 5, 6, 7};int n = sizeof(arr) / sizeof(arr[0]);heapSort(arr, n);printf("排序后的数组: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}return 0;
}​
2.3 时间和空间复杂度
  • 时间复杂度
    • 构建堆需要O(n)时间。
    • 排序过程需要O(n log n)时间。
    • 总体时间复杂度为O(n log n)
  • 空间复杂度
    • 原地排序,无额外空间需求,空间复杂度为O(1)
2.4 优点与缺点
  • 优点
    • 时间复杂度为O(n log n),无最坏情况。
    • 不需要额外存储空间,适合内存有限的场景。
  • 缺点
    • 不稳定排序。
    • 实现相对复杂,调整堆时需要更多代码。

三、对比与总结

特性归并排序堆排序
时间复杂度O(n log n)O(n log n)
空间复杂度O(n)O(1)
稳定性稳定不稳定
适用场景数据量大,且对稳定性有要求内存有限,且对稳定性无要求

四、总结与展望

归并排序和堆排序是经典的高级排序算法,各有优缺点。归并排序因其稳定性和良好的最坏情况表现适用于广泛场景,而堆排序因其原地排序特性在内存有限的情况下更具优势。

在下一篇文章中,我们将深入探讨线性时间排序算法(如计数排序、桶排序、基数排序),感受算法在特定场景下的极致效率,敬请期待!

归并排序与堆排序不仅是经典的排序算法,也是面试中经常被问到的重点。希望通过这篇文章,你能深入理解它们的原理与实现,为掌握高级排序算法迈出扎实的一步。
有疑问或建议?欢迎评论区讨论,我们一起进步!

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

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

相关文章

JVM调优之如何排查CPU长时间100%的问题

对于CPU长时间100%的问题&#xff0c;其实有一个比较标准的排查流程&#xff0c;现在模拟一个垃圾回收导致的cup占用率过高的排查方法。 步骤如下&#xff1a; 1.先通过top命令找到消耗cpu很高的进程id 在服务器上输入top&#xff0c;显示如下&#xff1a; 通过top命令定位到…

中间件--MongoDB部署及初始化js脚本(docker部署,docker-entrypoint-initdb.d,数据迁移,自动化部署)

一、概述 MongoDB是一种常见的Nosql数据库&#xff08;非关系型数据库&#xff09;&#xff0c;以文档&#xff08;Document&#xff09;的形式存储数据。是非关系型数据库中最像关系型数据库的一种。本篇主要介绍下部署和数据迁移。 在 MongoDB 官方镜像部署介绍中&#xff…

SkyWalking Helm Chart 4.7.0 安装、配置

https://skywalking.apache.org/events/release-apache-skywalking-kubernetes-helm-chart-4.7.0/https://github.com/apache/skywalking-helm/tree/v4.7.0https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/简介 skywalking 是分布式系统的 APM(Applicat…

HTA8998 实时音频跟踪的高效内置升压2x10W免电感立体声ABID类音频功放

1、特征 输出功率(fIN1kHz,RL4Ω&#xff0c;BTL) VBAT 4V, 2x10.6W(VOUT9V,THDN10%) VBAT 4V, 2x8.6W (VOUT9V,THDN1%) 内置升压电路模式可选择:自适应实时音频跟踪 升压(可提升播放时间50%以上)、强制升压 最大升压值可选择&#xff0c;升压限流值可设置 ACF防破音功能 D类…

时间敏感网络与工业通信的融合:光路科技电力专用交换机和TSN工业交换机亮相EP电力展

12月7日&#xff0c;第三十一届中国国际电力设备及技术展览会&#xff08;EP Shanghai 2024&#xff09;暨上海国际储能技术应用展览会在上海新国际博览中心圆满落幕。本届展会以“数字能源赋能新质生产力”为主题&#xff0c;系统地呈现了电力设备行业在技术融合、转型升级及上…

前端请求后端接口报错(blockedmixed-content),以及解决办法

报错原因&#xff1a;被浏览器拦截了&#xff0c;因为接口地址不是https的。 什么是混合内容&#xff08;Mixed Content&#xff09; 混合内容是指在同一页面中同时包含安全&#xff08;HTTPS&#xff09;和非安全&#xff08;HTTP&#xff09;资源的情况。当浏览器试图加载非…

【Golang】Go语言编程思想(六):Channel,第四节,Select

使用 Select 如果此时我们有多个 channel&#xff0c;我们想从多个 channel 接收数据&#xff0c;谁来的快先输出谁&#xff0c;此时应该怎么做呢&#xff1f;答案是使用 select&#xff1a; package mainimport "fmt"func main() {var c1, c2 chan int // c1 and …

SpringBoot【八】mybatis-plus条件构造器使用手册!

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 经过上一期的mybatis-plus 入门教学&#xff0c;想必大家对它不是非常陌生了吧&#xff0c;这期呢&#xff0c;我主要是围绕以下几点展开&#xff0c;重点给大家介绍 里…

算法-字符串-32.最长有效括号

一、题目 二、思路解析 1.思路&#xff1a; 滑动窗口&#xff01;&#xff01;&#xff01; 2.常用方法&#xff1a; 无 3.核心逻辑&#xff1a; 1.特殊情况&#xff1a;当字符串为空或不存在 if(snull||s.length()0)return 0; 2.一般情况 a.记录最长有效括符res&#xff1b;初…

9. Win11上原生运行Ubuntu

本文介绍如何在win11原生系统上运行ubuntu&#xff0c;不需要额外安装虚拟机&#xff0c;以及如何配置网络等。 1.安装正版Win11 由于正版Win11需要钱&#xff0c;网上能破解的win11可能有问题&#xff0c;但是它们的破解工具&#xff0c;却是能正常用的&#xff0c;所以&…

【CSS in Depth 2 精译_075】12.2 Web 字体简介 + 12.3 谷歌字体的用法

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 12.1.1 使用 em 还是 px12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 12.2 Web 字体 ✔️12.3 谷歌字体 ✔️12.…

【学习笔记】目前市面中手持激光雷达设备及参数汇总

手持激光雷达设备介绍 手持激光雷达设备是一种利用激光时间飞行原理来测量物体距离并构建三维模型的便携式高科技产品。它通过发射激光束并分析反射回来的激光信号&#xff0c;能够精确地获取物体的三维结构信息。这种设备以其高精度、适应各种光照环境的能力和便携性&#xf…

SQL汇总数据:聚集函数

我们经常需要汇总数据而无需实际检索出这些数据&#xff0c;为此SQL提供了专门的函数。使用这些函数&#xff0c;SQL查询能够高效地检索数据&#xff0c;以便进行分析和报表生成。这类检索的例子包括&#xff1a; 确定表中行数&#xff08;或者满足某个条件或包含某个特定值的…

Midjourney基础教程-功能界面详解

基础入门教程&#xff1a; 一.Midjourney快速入门(3步画出你的第一张图&#xff09; 注&#xff1a; 1.平台为大家设置了自动翻译&#xff0c;可以直接写中文提示词&#xff0c;自动翻译成英文。当然要求更准确&#xff0c;大家可以先翻译成英 文在输入进来。 2.提示词如何去…

初识Linux · 日志编写

目录 前言&#xff1a; 日志的简单说明 编写日志 前言&#xff1a; 在线程池部分我们纵观全文&#xff0c;可以发现全文有很多很多的IO流&#xff0c;看起来还是差点意思的&#xff0c;而我们今天提到的日志&#xff0c;是在今后的代码编写中会经常接触&#xff0c;或者说在…

微信小程序做电子签名功能

文章目录 最近需求要做就记录一下。 人狠话不多&#xff0c;直接上功能&#xff1a; 直接搂代码吧,复制过去就可以用&#xff0c;有其他需求自己改吧改吧。 signature.wxml <!-- 电子签名页面 --> <custom-navbar title"电子签名"show-home"{{fals…

【HarmonyOS】使用AVPlayer播放音乐,导致系统其它应用音乐播放暂停 - 播放音频焦点管理

【HarmonyOS】使用AVPlayer播放音乐&#xff0c;导致系统其它应用音乐播放暂停 - 播放音频焦点管理 一、前言 在鸿蒙系统中&#xff0c;对于音乐播放分为几种场景。音乐&#xff0c;电影&#xff0c;音效&#xff0c;闹钟等。当使用AVPlayer播放音乐时&#xff0c;如果不处理…

Linux中inode、软硬连接

磁盘的空间管理 如何对磁盘空间进行管理&#xff1f; 假设在一块大小为500G的磁盘中&#xff0c;500*1024*1024524288000KB。在磁盘中&#xff0c;扇区是磁盘的基本单位&#xff08;一般大小为512byte&#xff09;&#xff0c;而文件系统访问磁盘的基本单位是4KB&#xff0c;因…

基于卷积神经网络的垃圾分类系统实现(GUI应用)

1.摘要 本文主要实现了一个卷积神经网络模型进行垃圾图像分类&#xff0c;为了提高垃圾分类模型的准确率&#xff0c;使用使用Batch Normalization层、使用早期停止策略来防止过拟合等方法来优化模型&#xff0c;实验结果显示最终优化后的模型准确率较高90%左右。最终&#xf…

IDEA结合GitLab使用

GitLab新建仓库 使用管理员账号创建gitlab仓库创建空白文件填写项目名称及命名空间 注意&#xff1a;取消勾选【使用自述文件初始化仓库】&#xff0c;否则IDEA中push代码报错 设置仓库权限 【设置】-【仓库】-【受保护分支】中需要添加哪些角色可以提交与合并代码&#xff0…