当前位置: 首页 > news >正文

数据结构—排序算法篇三

本篇博客是归并排序的讲解和一些非比较排序的讲解。

归并排序你可能没怎么听说过,但是你可能听说过有序链表的合并、有序数组的合并。归并排序就是将两个有序数组进行排序,然后在放到新的数组里形成有序。

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序核心步骤:

在这里插入图片描述

那么问题来了,如何让两个数组有序?
用递归分解法:首先把一个数组分成两半,然后去递归左右区间,区间剩下一个数进行比较。

归并排序代码

//归并排序
void _MergeSort(int* a, int* tmp, int left, int right)
{if (left == right)return;int mid = (left + right) / 2;_MergeSort(a, tmp, left, mid);_MergeSort(a, tmp, mid + 1, right);int i = left;int begin1= left, end1= mid;int begin2 = mid + 1, end2 = right;//归并while (begin1<=end1&&begin2<=end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while(begin1<=end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + left, tmp + left, (right - left + 1)*sizeof(int));}

最后一定要归并一次拷贝一次,不然如果不拷贝,原数组就变化不了,从而导致排序失败!

归并排序非递归

原理和递归差不多,只不过是用循环代替递归。
通过循环建立分组,是数据进行归并
如下图:
在这里插入图片描述

归并排序非递归代码实现

//归并排序 非递归实现
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");return;}int gro = 1;while (gro < n){for (int i = 0;i < n;i += 2 * gro){int begin1 = i, end1 = i + gro - 1;int begin2 = i + gro, end2 = i + 2 * gro - 1;//归并if (begin2 >= n)break;if (end2 >= n)end2 = n - 1;int j = i;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));}gro = gro * 2;}free(tmp);tmp = NULL;
}

最后说一下归并排序的时间复杂度是O(N*logN);空间复杂度是O(N);

非比较排序

非比较排序是一种较为特殊的排序,非比较排序是不通过元素间直接比较来排序的算法,核心优势是在特定数据场景下时间复杂度突破 O (n log n) 下限。

下面来看看三种非比较排序

  1. 计数排序
    适用场景:数据范围 k 远小于元素个数 n,且数据为非负整数。
    核心逻辑:统计每个数值出现的次数,再根据次数依次输出元素。
  2. 桶排序
    适用场景:数据分布均匀,可划分成多个有序 “桶”。
    核心逻辑:将数据分到不同桶中,对每个桶单独排序(可结合比较排序),最后合并所有桶。
  3. 基数排序
    适用场景:数据可按位拆分(如数字、字符串),且每位的取值范围有限。
    核心逻辑:按低位到高位(或反之)依次排序,每一轮用稳定排序(如计数排序)处理当前位。

计数排序

计数排序是非比较排序中最基础、最常用的算法,核心是通过 “统计元素出现次数” 来直接确定每个元素的最终位置,完全不依赖元素间的大小比较。它的优势是在数据范围可控时,能达到 O (n + k) 的线性时间复杂度(n 是元素个数,k 是数据最大值与最小值的差值),但缺点是对数据类型和范围有严格限制。通俗来讲就是统计数组元素出现的次数,再将他们统一排序

计数排序实现

void CountSort(int* a, int n)
{//选择区间int min = a[0], max = a[0];for (int i = 1;i < n;i++){if (a[i] > max){max = a[i];}if (min > a[i]){min = a[i];}}//申请空间int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));if (count == NULL){perror("count fail");return;}//排序for (int i = 0;i < n;i++){count[a[i] - min]++;}int j = 0;for (int i = 0;i < range;i++){while (count[i]--){a[j++] = i + min;}}
}

最后总结 计数排序不适用空间过大的数据排序,不适用浮点数排序

基数排序

基数排序(Radix Sort)是基于 “位” 排序的非比较排序,核心是按数字的每一位(或字符的每一位)依次排序,借助稳定排序(如计数排序)保证每一轮排序的有效性。它突破了比较排序的 O (n log n) 下限,时间复杂度为 O (d×(n + k))(d 是最大元素的位数,k 是每一位的取值范围),通用性比计数排序更强。
简单来说比如都是三位数的比较,先比较个位,在比较十位,在比较百位最后让他们有序,日常中有前几大排序 基本用不到基数排序。

桶排序

桶排序(Bucket Sort)是一种非比较排序算法,它通过将数据分到有限数量的有序 “桶” 中,分别对每个桶进行排序,最后合并结果来完成整体排序。
如下图:将他们分别放入桶中在进行排序
请添加图片描述

在这里插入图片描述
最后 非比较排序其实不是太重要,因为有更好的排序可以替代。所以这里简略描述一下。排序三部曲也是结束了,有些排序描述的不太好,因为太抽象了,所以尽力了。

http://www.dtcms.com/a/580975.html

相关文章:

  • 从“医疗大模型”向“医疗智能体”架构与路径分析(白皮书草案-上)
  • LeetCode算法日记 - Day 95: 回文子串
  • DockerCompose与多容器编排
  • AngularJS与SQL的集成使用指南
  • 【ZeroRange WebRTC】TWCC 在 WebRTC 中的角色与工作原理(深入指南)
  • 数据结构常见的八大排序算法
  • 个人怎么做网站app推广引流方法
  • 初识光伏逆变器
  • 一文了解LLM应用架构:从Prompt到Multi-Agent
  • MongoDB 内存管理避坑指南:解决高占用、页错误等核心问题,让数据库性能翻倍
  • 关于DNS中毒攻击的解决方案分享
  • 【C++】数据挖掘算法在软件测试中的应用
  • WebSocket 完全指南:从原理到实战,搭建实时通信桥梁
  • STM32项目分享:智能水产养殖系统
  • 网站开发线框个体营业执照网上年报
  • iPhone苹果手机拍的照片默认是heic如何换成jpg格式
  • 基于微信小程序的旅游攻略分享互动平台设计与实现-项目分享
  • Neo4j Windows桌面版安装及更改默认数据存储位置
  • 智能安防新篇章:EasyGBS助力重塑物业视频管理服务
  • ps2017做网站当阳网站建设电话
  • H5短视频SDK,赋能Web端视频创作革命
  • 如何选择温州本凡科技进行小程序开发服务?
  • 融智兴科技邀您共赴2025中国洗涤展
  • STM32上使用HAL库完美实现驱动MAX98357声卡模块(I2S+DMA+音频环形缓冲区)
  • 【React】打卡笔记,入门学习03:useState、useEffect、useRef、useMemo
  • M|烟花 (1995)
  • 平顶山网站建设2022年黄台片区
  • 人工智能的未来之路:华为全栈技术链与AI Agent应用实践
  • 基于openresty反向代理、dns劫持、实现对http请求、响应内容抓包
  • 智能体的范式革命:华为全栈技术链驱动下一代AI Agent