【数据结构】排序算法——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.mzph.cn/news/874843.shtml

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

相关文章

uni-app pinia搭建

1.新建store文件 新建index.js&#xff0c;代码&#xff1a; // import { // createPinia // } from pinia //const store createPinia() import * as Pinia from pinia const pinia Pinia.createPinia() export * from "./modules/user" export * from ".…

vscode 寻找全部分支的提交

vscode 寻找全部分支的提交 Git Graph

Python 机器学习求解 PDE 学习项目——PINN 求解二维 Poisson 方程

本文使用 TensorFlow 1.15 环境搭建深度神经网络&#xff08;PINN&#xff09;求解二维 Poisson 方程: 模型问题 − Δ u f in Ω , u g on Γ : ∂ Ω . \begin{align} -\Delta u & f \quad & \text{in } \Omega,\\ u & g \quad & \text{on } \Gamma:\p…

Proxmox8基于PC物理机/服务器安装,初始化,挂载磁盘,安装虚拟机

目录 安装文件 开始安装Proxmox 选择启动菜单&#xff0c;F11 后进入启动菜单选择 按需选择是否关闭RAID 选择对应的U盘 进入安装界面 进入安装启动过程 选择系统盘 设置相关信息 设置IP和开启root远程登录 设置dns 设置网卡ip 设置 ssh 远程登录 开机合并local-l…

Telegram曝零日漏洞,可伪装成视频攻击安卓用户

ESET Research在一个地下论坛上发现了一个针对Android Telegram的零日漏洞广告。 ESET将该漏洞命名为“EvilVideo”&#xff0c;并将其报告给Telegram&#xff0c;Telegram于7月11日更新了该应用程序。 EvilVideo允许攻击者发送恶意的有效载荷&#xff0c;这些载荷以视频文件…

计算机网络-配置双机三层互联(静态路由方式)

目录 交换机工作原理路由器工作原理路由信息表组成部分路由器发决策 ARP工作原理配置双机三层互联&#xff08;静态路由方式&#xff09; 交换机工作原理 MAC自学习过程 初始状态&#xff1a; 刚启动的交换机的MAC地址表是空的。 学习过程&#xff1a; 当交换机收到一个数据帧…

论文阅读——Integrated Diffusive Antenna Array of Low Backscattering

文章目录 摘要一、背景介绍二、天线结构A. 缝隙天线B. 低频扩散单元C. 高频扩散单元D. 集成设计 三、验证总结 论文来源&#xff1a;https://ieeexplore.ieee.org/document/10309141 摘要 文章提出了一种低雷达散射截面&#xff08;RCS&#xff09;的扩散天线阵列。 作为示例…

STM32嵌入式人工智能边缘计算应用教程

目录 引言环境准备边缘计算系统基础代码实现&#xff1a;实现嵌入式人工智能边缘计算系统 4.1 数据采集模块 4.2 数据处理与推理模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;边缘计算与优化问题解决方案与优化收尾与总结 1. 引言 嵌入式人工智…

前后端分离项目部署,vue--nagix发布部署,.net--API发布部署。

目录 Nginx免安装部署文件包准备一、vue前端部署1、修改http.js2、npm run build 编译项目3、解压Nginx免安装,修改nginx.conf二、.net后端发布部署1、编辑appsetting.json,配置跨域请求2、配置WebApi,点击发布3、配置文件发布到那个文件夹4、配置发布相关选项5、点击保存,…

Python-numpy基础--------2

1.full()创建函数 目录 1.full()创建函数 2.创建单位矩阵 3.linspace创建 4.logspace 创建 5.二维数组的索引和切片&#xff1a; 1.索引直接获取 在NumPy中&#xff0c;full() 函数用于创建一个给定形状、类型的新数组&#xff0c;并用指定的值填充这个数组。这个函数非…

【vue前端项目实战案例】Vue3仿今日头条App

本文将开发一款仿“今日头条”的新闻App。该案例是基于 Vue3.0 Vue Router webpack TypeScript 等技术栈实现的一款新闻资讯类App&#xff0c;适合有一定Vue框架使用经验的开发者进行学习。 项目源码在文章末尾 1 项目概述 该项目是一款“今日头条”的新闻资讯App&#xf…

go语言day14 bufio包 ioutil包

Golang-100-Days/Day16-20(Go语言基础进阶)/day16_file操作.md at master rubyhan1314/Golang-100-Days GitHub 一、bufio包 读写文件 1&#xff09; bufio包下的Reader类实现了Read()方法和Write()方法 2&#xff09;和io包相比&#xff0c;虽然都是在读写文件&#xff0c;…

【Android】性能实践—编码优化与布局优化学习笔记

【Android】性能实践—编码优化与布局优化学习笔记 编码优化 使用场景 如果需要拼接字符串&#xff0c;优先使用StringBuffer和StringBuilder进行凭借&#xff0c;他们的性能优于直接用加号进行拼接&#xff0c;因为使用加号连接符会创建多余的对象一般情况下使用基本数据类…

Unity扩展SVN命令

可以直接在unity里右键文件提交和查看提交记录 顶部菜单栏上回退和更新整个unity工程 SvnForUnity.CS 记得要放在Editor文件夹下 using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using UnityEditor; using Unity…

Era3D 论文学习

代码地址&#xff1a;https://penghtyx.github.io/Era3D/ 论文地址&#xff1a;https://arxiv.org/abs/2405.11616 解决了什么问题&#xff1f; 尽管多视角内容生成领域取得了显著的进展&#xff0c;但现有的方案仍然面临着相机先验不匹配、效果差、分辨率低等问题&#xff0…

windows USB 设备驱动开发- 对 MUTT 设备进行 BIOS/UEFI 测试

对 MUTT 设备进行 BIOS/UEFI 测试&#xff0c;BIOS/UEFI 测试验证 USB 启动以及控制器到操作系统的切换。 USB 启动配置 在 USB 2.0 (EHCI) 和 USB 3.0 (xHCI) 控制器上执行这些测试&#xff0c;每种主要 USB 媒体类型 &#xff0c;USB 2.0 BOT、USB 3.0 BOT 和 USB 3.0 UASP…

【Android】ListView和RecyclerView知识总结

文章目录 ListView步骤适配器AdpterArrayAdapterSimpleAdapterBaseAdpter效率问题 RecyclerView具体实现不同布局形式的设置横向滚动瀑布流网格 点击事件 ListView ListView 是 Android 中的一种视图组件&#xff0c;用于显示可滚动的垂直列表。每个列表项都是一个视图对象&…

Python教程(一):环境搭建及PyCharm安装

目录 引言1. Python简介1.1 编译型语言 VS 解释型语言 2. Python的独特之处3. Python应用全览4. Python版本及区别5. 环境搭建5.1 安装Python&#xff1a; 6. 开发工具&#xff08;IDE&#xff09;6.1 PyCharm安装教程6.2 永久使用教程 7. 编写第一个Hello World结语 引言 在当…

每日一题 LeetCode03 无重复字符的最长字串

1.题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长字串的长度。 2 思路 可以用两个指针, 滑动窗口的思想来做这道题,即定义两个指针.一个left和一个right 并且用一个set容器,一个length , 一个maxlength来记录, 让right往右走,并且用一个set容器来…

如何避免蓝屏?轻量部署,安全和业务连续性才能两不误

自19日起&#xff0c;因CrowdStrike软件更新的错误配置而导致的“微软全球蓝屏”&#xff0c;影响依然在持续。这场被称为“史上最大规模的IT故障”&#xff0c;由于所涉全球企业太多&#xff0c;专家估计“蓝屏”电脑全部恢复正常仍需时日。 尽管 CEO 乔治 库尔茨&#xff08…