【数据结构】排序算法——Lesson2

Hi~!这里是奋斗的小羊,很荣幸您能阅读我的文章,诚请评论指点,欢迎欢迎 ~~
💥💥个人主页:奋斗的小羊
💥💥所属专栏:C语言

🚀本系列文章为个人学习笔记,在这里撰写成文一为巩固知识,二为展示我的学习过程及理解。文笔、排版拙劣,望见谅。


目录

  • 前言
  • 一、排序算法
    • 1、归并排序
    • 2、归并非递归
    • 3、计数排序
    • 4、排序算法复杂度及稳定性分析
  • 总结

前言

本文将继续介绍两种高效的排序算法——归并排序、计算排序。
归并排序在一些场合下(如外部排序)非常有效,当数据量非常大且无法全部加载到内存时,可以将其分块处理。
而计数排序是一种非比较排序算法,适用于特定范围内的整数排序,在许多数情况下计算排序可以秒杀我们介绍过的所有排序。


一、排序算法

1、归并排序

| 算法思路:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列间段有序。

在这里插入图片描述

动图演示:

请添加图片描述

代码实现:

//子函数
void _MergeSort(int* arr, int* tmp, int begin, int end)
{if (begin == end){return;}int mid = (begin + end) / 2;//[begin, mid]  [mid + 1, end]_MergeSort(arr, tmp, begin, mid);_MergeSort(arr, tmp, mid + 1, end);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[i++] = arr[begin1++];}else{tmp[i++] = arr[begin2++];}}while (begin1 <= end1){tmp[i++] = arr[begin1++];}while (begin2 <= end2){tmp[i++] = arr[begin2++];}memcpy(arr + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}//归并排序
void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");return;}_MergeSort(arr, tmp, 0, n - 1);free(tmp);tmp = NULL;
}

归并排序有几个需要特别注意的点:

  • 分割区间一定要按[begin, mid] [mid + 1, end]分,不然会导致死循环
  • memcpy(arr + begin, tmp + begin, (end - begin + 1) * sizeof(int));
  • 一定是归并一组拷贝一组,因为如果存在越界的情况还整体拷贝肯定会出错
  • 归并排序算法的时间复杂度是:O(N*logN),空间复杂度是:O(N).

2、归并非递归

递归改非递归有两种办法,一种是用栈模拟,一种是用循环处理。

上篇文章中快排非递归我们是利用栈实现的,但是归并的非递归使用栈解决不了,因为快排的递归过程是一个类似前序遍历的过程,而归并是一个类似后续的过程,它是先将区间循环分割成只有一个数据,再反向进行归并,栈是做不到这一点的。
所以归并的非递归我们考虑用循环来实现。

我们可以直接将原数组一一归并,再二二归并,再四四归并……

请添加图片描述

//归并非递归
void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");return;}//gap是每组归并数据的个数int gap = 1;while (gap < n){//i表示每组归并的起始位置for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;int j = i;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[j++] = arr[begin1++];}else{tmp[j++] = arr[begin2++];}}while (begin1 <= end1){tmp[j++] = arr[begin1++];}while (begin2 <= end2){tmp[j++] = arr[begin2++];}//memcpy(arr + i, tmp + i, (end2 - i + 1) * sizeof(int));}gap *= 2;//一一归,二二归,四四归}free(tmp);tmp = NULL;
}
  • memcpy(arr + i, tmp + i, (end2 - i + 1) * sizeof(int));
  • for (int i = 0; i < n; i += 2 * gap)
  • int begin2 = i + gap, end2 = i + 2 * gap - 1;

但是上面的代码还不完善,仅限2的次方个数的数据归并,如果不是2的次方个数则会越界。越界无非下面三种情况:

  1. [begin1, end1] [begin2, end2 ]
  2. [begin1, end1] [begin2 , end2 ]
  3. [begin1, end1 ] [begin2 , end2 ]

其中第二种和第三种可以归为一类,因为begin2越界说明我们需要排序的数据已经排好序了,越界的部分不是我们的区间我们根本不用管,直接退出循环就行了。
而第一种情况只需要处理一下就好,让end2变成n - 1就行了。

代码示例:

//归并非递归
void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(n * sizeof(int));if (tmp == NULL){perror("malloc fail");return;}//gap是每组归并数据的个数int gap = 1;while (gap < n){//i表示每组归并的起始位置for (int i = 0; i < n; i += 2 * gap){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;//第二组都越界,不存在,不是我们需要排序的数据if (begin2 >= n){break;}//begin2没越界,end2越界,只需要修正一下就好if (end2 >= n){end2 = n - 1;}int j = i;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[j++] = arr[begin1++];}else{tmp[j++] = arr[begin2++];}}while (begin1 <= end1){tmp[j++] = arr[begin1++];}while (begin2 <= end2){tmp[j++] = arr[begin2++];}//归并一次拷贝一次memcpy(arr + i, tmp + i, (end2 - i + 1) * sizeof(int));}gap *= 2;}free(tmp);tmp = NULL;
}

3、计数排序

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用。其排序步骤为:

1. 统计相同元素出现的次数,将统计到的次数作为count数组以元素值对应下标处的值
2. 根据统计的结果将序列回收到原来的序列中
3. 动态开辟的count数组要初始化为全0

本质: 利用count数组的自然序号排序

为了保证开辟大小合适的count数组,我们可以用待排数据中最大值减最小值加一的方法来确定一个合适的范围(max - min + 1)。
然后再用元素值减去最小值的方法来和count数组形成相对映射关系(arr[i] - min),得到的值是几就在数组对应下标位置递增。
最后一步排序的时候不要忘了在原数组中插入的值还要加上最小值,并且count数组中下标对应位置的值是几就循环几次,如果对应位置是0的话说明原数组没有这个下标数,就不进入循环。

大致思想如下:

请添加图片描述

代码如下:

//计数排序
void CountSort(int* arr, int n)
{int min = arr[0];int max = arr[0];for (int i = 1; i < n; i++){if (arr[i] < arr[min]){min = arr[i];}if (arr[i] > arr[max]){max = arr[i];}}int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));if (count == NULL){perror("calloc fail");return;}//统计次数for (int i = 0; i < n; i++)//遍历原数组{count[arr[i] - min]++;}//排序int j = 0;for (int i = 0; i < range; i++)//遍历count数组{while (count[i]--){arr[j++] = i + min;}}free(count);count = NULL;
}

计数排序的时间复杂度为:O(N + range),相比较前几种排序算法,计数排序效率是非常高的,但速度快的同时也有空间消耗,计数排序的空间复杂度为:O(range),所以计数排序也算是拿空间换时间。

计数排序虽然相对其他排序算法快且稳定,但也存在一些缺陷:

  • 只能排整数,不能排浮点数
  • 要求数据比较集中,不然空间开销太大

4、排序算法复杂度及稳定性分析

稳定性: 如果待排序数据中有多个相同的的数据,若经过排序这些相同的数据相对位置保持不变,则称这种排序算法是稳定的。

排序算法时间复杂度空间复杂度稳定性
插入排序O(N^2)O(1)稳定
希尔排序O(N^1.3)O(1)不稳定
选择排序O(N^2)O(1)不稳定
堆排序O(N*logN)O(1)不稳定
冒泡排序O(N^2)O(1)稳定
快速排序O(N*logN)O(logN)不稳定
归并排序O(N*logN)O(N)稳定
计数排序O(N + range)O(range)稳定

总结

  • 这些排序算法各有千秋,在某些特定的情况下某个算法的性能尤为突出,在一些复杂的排序中为了追求性能往往使用混合排序,这使得性能大大提高。

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

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

相关文章

算法力扣刷题记录 五十七【236. 二叉树的最近公共祖先】和【235. 二叉搜索树的最近公共祖先】

前言 公共祖先解决。二叉树和二叉搜索树条件下的最近公共祖先。 二叉树篇继续。 一、【236. 二叉树的最近公共祖先】题目阅读 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff…

Windows 磁盘分区样式有几种?如何查看电脑分区样式?

在使用 Windows 操作系统的过程中&#xff0c;磁盘分区是一个重要的概念。磁盘分区的方式直接影响到数据存储和系统运行的效率。磁盘分区的时候也有不同的样式&#xff0c;你知道分区类型有哪些吗&#xff1f;不同的分区样式决定了硬盘的分区方式、可支持的最大存储容量以及兼容…

学习笔记:MySQL数据库操作3

1. 创建数据库和表 创建数据库 mydb11_stu 并使用该数据库。创建 student 表&#xff0c;包含字段&#xff1a;学号&#xff08;主键&#xff0c;唯一&#xff09;&#xff0c;姓名&#xff0c;性别&#xff0c;出生年份&#xff0c;系别&#xff0c;地址。创建 score 表&…

Etsy:以手工制品和复古商品闻名的美国淘宝允许AI艺术品售卖

Etsy是一个美国网络商店平台&#xff0c;以手工艺成品买卖为主要特色&#xff0c;曾被纽约时报拿来和eBay&#xff0c;Amazon比较&#xff0c;被誉为“祖母的地下室收藏”。 Etsy 是一家以手工制品和复古商品闻名的美国网络商店平台在线市场&#xff0c;以手工艺成品买卖为主要…

由“微软蓝屏”事件引发的对网络安全与系统稳定性的思考

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、软件更新流程的漏洞与改进二、强化应急响应机制三、技术创新与应用四、关键行业的特殊应对五、用户意识的提升与数据备份六、全球合作与统一标准总结 前言 …

浅谈断言之XML断言

浅谈断言之XML断言 XML断言是JMeter的一个组件&#xff0c;用于验证请求的响应数据是否符合XML结构。这对于测试返回XML格式数据的Web服务特别有用。 如何添加XML断言&#xff1f; 要在JMeter测试计划中添加XML断言&#xff0c;遵循以下步骤&#xff1a; 打开测试计划&…

The Sandbox:虚拟游戏世界生态系统详解

元宇宙由区块链、软件基础、移动应用、控制台等组成&#xff0c;是一个虚拟空间&#xff0c;结合了增强现实&#xff08;AR&#xff09;、虚拟现实&#xff08;VR&#xff09;和在线游戏等元素。它强调互操作性&#xff0c;允许用户在不同的虚拟平台之间自由切换。与传统的现实…

病理AI领域的常用开源工具汇总

小罗碎碎念 本期推文主题&#xff1a;病理AI领域的常用开源工具汇总 我们有快一周的时间没见啦&#xff0c;所以&#xff0c;这一期推文带来一些比较有实用价值的资源。 我总结了5个病理AI领域常用的软件&#xff0c;用专用于注释的&#xff0c;也有包含整个处理流程的&#x…

【Linux】UDP 协议

目录 1. UDP 协议2. UDP 协议的特点:3. UDP 协议的格式4. UDP 的缓冲区基于UDP的应用层协议 1. UDP 协议 UDP (User Datagram Protocol) 是一种面向数据报的传输层协议, 是传输层的重要协议之一; UDP协议提供了一种无连接, 不可靠的数据传输服务; 适用于要求源主机以恒定速率…

主控制类,项目小结,实时更新UI

1.用户的信息进行更改&#xff0c;上传请求&#xff0c;服务端进行直接操作数据库&#xff0c;返回请求&#xff0c;客户端根据返回的请求&#xff0c;进行更新界面。 按照我前一篇所说的&#xff0c;写好了主控制类&#xff0c;和第二线程接受服务端的信息&#xff0c;这时候…

【Hot100】LeetCode—416. 分割等和子集

目录 题目1- 思路2- 实现⭐152. 乘积最大子数组——题解思路 3- ACM 实现 题目 原题连接&#xff1a;416. 分割等和子集 1- 思路 理解为背包问题 思路&#xff1a; 能否将均分的子集理解为一个背包&#xff0c;比如对于 [1,5,11,5]&#xff0c;判断能否凑齐背包为 11 的容量…

leetcode算法题之接雨水

这是一道很经典的题目&#xff0c;问题如下&#xff1a; 题目地址 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 解法1&#xff1a;动态规划 动态规划的核心就是将问题拆分成若干个子问题求解&#…

2024算法、高性能计算与人工智能国际学术会议(AHPCAI 2024)

2024算法、高性能计算与人工智能国际学术会议&#xff08;AHPCAI 2024&#xff09; 2024 International Conference on Algorithms, High Performance Computing and Artificial Intelligence 2024年8月14-16日 | 中国-郑州 2024中国算力大会正在发起“算力中国最佳学术论文…

今天我们聊聊C#的并发和并行

并发和并行是现代编程中的两个重要概念&#xff0c;它们可以帮助开发人员创建高效、响应迅速、高性能的应用程序。在C#中&#xff0c;这些概念尤为重要&#xff0c;因为该语言提供了对多线程和异步编程的强大支持。本文将介绍C#中并发和并行编程的关键概念、优点&#xff0c;并…

Langchain核心模块与实战[7]:专业级Prompt工程调教LLM[输入输出接口、提示词模板与例子选择器的协同工程]

Langchain核心模块与实战[7]:专业级Prompt工程调教LLM[输入输出接口、提示词模板与例子选择器的协同工程] 1. 大模型IO接口 任何语言模型应用的核心元素是…模型的输入和输出。LangChain提供了与任何语言模型进行接口交互的基本组件。 提示 prompts : 将模型输入模板化、动态…

【LeetCode:3096. 得到更多分数的最少关卡数目+ 前缀和】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

百度,有道,谷歌翻译API

API翻译 百度&#xff0c;有道&#xff0c;谷歌API翻译&#xff08;只针对中英相互翻译&#xff09;,其他语言翻译需要对应from&#xff0c;to的code 百度翻译 package fills.tools.translate; import java.util.ArrayList; import java.util.HashMap; import java.util.Lis…

宠物空气净化器哪款除臭效果好?质量好的养狗空气净化器排名

作为一个宠物家电小博主&#xff0c;炎炎夏日&#xff0c;家中的宠物给你带来的不仅仅是温暖的陪伴&#xff0c;还有那挥之不去的宠物异味。普通空气净化器虽然能够应对一般的空气净化需求&#xff0c;但对于养猫家庭特有的挑战&#xff0c;如宠物毛发、皮屑和异味等&#xff0…

大模型微调部署实战及类GPT工具的高效使用

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…

CSS3雷达扫描效果

CSS3雷达扫描效果https://www.bootstrapmb.com/item/14840 要创建一个CSS3的雷达扫描效果&#xff0c;我们可以使用CSS的动画&#xff08;keyframes&#xff09;和transform属性。以下是一个简单的示例&#xff0c;展示了如何创建一个类似雷达扫描的动画效果&#xff1a; HTM…