归并排序/计数排序
1:归并排序
1.1:代码
void _MergeSort(int* arr, int left, int right, int* tmp)
{if (left >= right){return;}int mid = (left + right) / 2; _MergeSort(arr, left, mid, tmp); _MergeSort(arr, mid+1, right, tmp); int begin1 = left; int end1 = mid; int begin2 = mid + 1; int end2 = right; int i = begin1; while (begin1 <= end1 && begin2 <= end2) { if(arr[begin1] < arr[begin2]) { tmp[i++] = arr[begin1++]; } if (arr[begin1] > arr[begin2]) { tmp[i++] = arr[begin2++]; } } while (begin1 <= end1) { tmp[i++] = arr[begin1++]; } while (begin2 <= end2) { tmp[i++] = arr[begin2++]; } for (int i = left; i <= right; i++) { arr[i] = tmp[i]; }
}void MergeSort(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n); _MergeSort(arr, 0, n - 1, tmp);
}
1.2:递归过程
图一:
if (left >= right){return;}int mid = (left + right) / 2; _MergeSort(arr, left, mid, tmp); _MergeSort(arr, mid+1, right, tmp);
通过这三行代码,可以得到如图所示的结果,当传递的 left 和 right 满足 if 条件时,递归开始返回,
图二:
注:方框内容为自定义函数:void _MergeSort(int* arr, int left, int right, int* tmp)
注:对于新手(编者我而言)需要知道的是,每次递归,都会向系统开辟新的空间,而原先的空间会临时贮存在空间中,通过return返回重新调用该函数。
第一次返回时,来到D这个位置,接下来就将执行排序,即如下代码:该函数中 left = 0 mid = 0 right = 1,是对两个元素进行排列。
int begin1 = left;
int end1 = mid;
int begin2 = mid + 1;
int end2 = right; int i = begin1;
while (begin1 <= end1 && begin2 <= end2)
{ if(arr[begin1] < arr[begin2]) { tmp[i++] = arr[begin1++]; } if (arr[begin1] > arr[begin2]) { tmp[i++] = arr[begin2++]; }
} while (begin1 <= end1)
{ tmp[i++] = arr[begin1++];
}
while (begin2 <= end2)
{ tmp[i++] = arr[begin2++];
}
当前范围内的数组排列完毕时,需要将临时数组的值传递给原数组,以便于下一次继续比较排序,
代码如下:
for (int i = left; i <= right; i++)
{ arr[i] = tmp[i];
}
left 和 right 分别对应数组左右临界,而left ~ right 中间的范围正是需要赋值的对象。
当D排序完毕后,系统会将其释放,此时来到B处,开始对右边数组开始递归,直至return,与左边递归类似,如图三所示:
图三:
当D中和E中的数组全部排列完毕,并且赋值给原数组时,此时会返回到B,对B中数组元素进行排列,,最后我们能够得到如下图所示的结果:
图四:
到B中函数排列完毕,并将临时数组中的值赋值给arr时,此时系统会将其空间释放,并返回到A中,开始递归右边部分函数,其过程如下图所示。
图五:
而对于右半部分的递归与左半部分相似,对于新人而言(我)注意其左临界值left的变化即可,其次通过上述过程不难发现,归并排序其实是一个后序遍历二叉树结点的过程,通过对左右子节点中的数组元素进行排列,最终在根节点处再次排列得到有序数组。
1.3:归并排序特性总结
时间复杂度:O(nlogn)
空间复杂度:O(n) —— 至于为什么是 n 而不是 logn 是因为以malloc 开辟了一块 n 大小的内存空间
2:计数排序
2.1:代码
void CountSort(int* arr, int n)
{ int max, min;max = min = arr[0];for (int i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}int range = max - min + 1;int* tmp = (int*)malloc(sizeof(int) * range);assert(tmp);memset(tmp, 0, sizeof(int) * range);for (int i = 0; i < n; i++){tmp[arr[i] - min]++;}int index = 0;for (int i = 0; i < range; i++){while (tmp[i]--){arr[index++] = i + min;}}
}
2.2:思路
计数排序的思想:先找到数组中的最大值和最小值,定义 range (range = max - min +1) 个大小空间的数组 ,为了是大数据能够更好的存放进数组,同时又不会浪费太多空间。
我们需要把原数组的数据 - min 存放进新数组相应位置处,原数组中每重复一个数字,新数组相应位置处的大小就+1,这就意味着计数排序要求原数组中,各个数据相差不是很大,否则会造成空间的浪费。
计数排序的巧妙在于,我们不用去比较各个元素然后排序,而是统计原数组中,每个元素出现的次数,并将该元素 - min (这个差对应新数组下标)存入到数组中,如果两个值相差不大 ,得到的差会对应于新数组的一个下标,即新数组中,统计的是该元素在原数组中出现的次数,最后我们再进行排序时,以新数组元素个数为条件出发,同时新数组下标+min 又可以得到原数组中的元素,从而实现排列。
2.3:代码分析
下列代码我们开辟了一块 range 大小的空间区域
int max, min;max = min = arr[0];for (int i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}int range = max - min + 1;int* tmp = (int*)malloc(sizeof(int) * range);assert(tmp);memset(tmp, 0, sizeof(int) * range);
下列代码统计了原数组中,每个元素出现的次数,并存入到临时数组中
for (int i = 0; i < n; i++)
{tmp[arr[i] - min]++;
}
最后对临时数组进行访问,以临时数组中元素个数为条件,临时数组下标地址 + min 得到原数组的值:
int index = 0;
for (int i = 0; i < range; i++)
{while (tmp[i]--){arr[index++] = i + min;}
}
2.4:图示上述过程:
初始时如图所示:
当进入第二个for循环时,开始统计原数组中的元素个数,当循环结束时,得到如下图所示变量关系:
当进入第三个for循环时,遍历tmp中各个元素,同时内层以各个元素的值作为条件,循环的将 i + min (原数组对应值) 赋值给原数组中,当外层 for 循环完成对数组的遍历时,此时原数组也得到了正确的顺序。
2.5:计数排序的特性
适用范围:数据范围比较集中时,效率很高
时间复杂度:O(N+range)
空间复杂度:O(range)
相关文章:

归并排序/计数排序
1:归并排序 1.1:代码 void _MergeSort(int* arr, int left, int right, int* tmp) {if (left > right){return;}int mid (left right) / 2; _MergeSort(arr, left, mid, tmp); _MergeSort(arr, mid1, right, tmp); int begin1 left…...

etcdctl defrag 剔除、添加etcd节点
零、准备工作 find / -name etcdctl cp /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/12/fs/usr/local/bin/etcdctl /usr/local/bin/etcdctlalias ec"etcdctl --endpointshttps://127.0.0.1:2379 --cacert /etc/kubernetes/pki/etcd/ca.crt --…...

计算机网络(二) —— 网络编程套接字
目录 一,认识端口号 1.1 背景 1.2 端口号是什么 1.3 三个问题 二,认识Tcp协议和Udp协议 三,网络字节序 四,socket编程接口 4.1 socket常见API 4.2 sockaddr结构 一,认识端口号 1.1 背景 问题:在进…...

二百五十九、Java——采集Kafka数据,解析成一条条数据,写入另一Kafka中(一般JSON)
一、目的 由于部分数据类型频率为1s,从而数据规模特别大,因此完整的JSON放在Hive中解析起来,尤其是在单机环境下,效率特别慢,无法满足业务需求。 而Flume的拦截器并不能很好的转换数据,因为只能采用Java方…...

Qt项目使用Inno Setup打包(关于打包中文乱码的解决)
关于打包好的文件乱码解决方法 打包好的文件中文乱码,就是编码格式出现了问题,更改一下中文脚本编码格式,在官网Inno Setup Translations下载好中文脚本 点击下载,然后另存为 得到ChineseSimplified.isl.txt文件后&#…...
HTML和HTML5有什么区别
HTML(超文本标记语言)是构建网页的基础,而HTML5是HTML的最新版本。虽然HTML和HTML5在许多方面相似,但HTML5引入了许多新的特性和改进,使得网页开发更加高效和功能丰富。 一、HTML概述 HTML,即超文本标记语…...
Collections
Collections 是 Java 中的一个实用工具类,提供了一系列静态方法来操作集合。以下是其详细介绍: 前置知识 在 Java 中,可变参数(Varargs)允许方法接受可变数量的参数。使用可变参数时,可以传递任意数量的参…...
fastreport打印trichedit分页问题的解决
用fastreport来打印richedit里面的内容。刚开始放一个frxrichview组件到报表上,然后在 var str: TMemoryStream; begin begin str: TMemoryStream.Create; CurrRichRecord.richedit.Lines.SaveToStream(str); str.Position: 0; tfrxRichview(fr…...

【MeterSphere】vnc连接不上selenium-chrome容器
目录 一、现象 二、查看配置文件 docker-compose-seleniarm.yml 三、处理 3.1 删除上图当中的三行 3.2 msctl reload 3.3 重新连接 前言:使用vnc连不上ms的selenium-chrome容器,看不到里面运行情况,以前其实可以,后来不行…...

mysql explain分析
目录 思维导图 id select_type SIMPLE PRIMARY SUBQUERY DEPENDENT SUBQUREY UNCACHEABLE SUBQUREY: UNION UNION RESULT DERIVED MATERIALIZED table partitions type ALL index range ref eq_ref const system possible_keys keys key_l…...
[论文笔记]Circle Loss: A Unified Perspective of Pair Similarity Optimization
引言 为了理解CoSENT的loss,今天来读一下Circle Loss: A Unified Perspective of Pair Similarity Optimization。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 这篇论文从对深度特征学习的成对相似度优化角度出发,旨在最大化同类之间…...

Windows .NET8 实现 远程一键部署,几秒完成发布,提高效率 - CICD
1. 前言 场景 (工作环境 一键部署 到 远端服务器 [阿里云]) CICD 基本步骤回顾 https://blog.csdn.net/CsethCRM/article/details/141604638 2. 环境准备 服务器端IP:106.15.74.25(阿里云服务器) 客户端࿱…...

echarts 水平柱图 科技风
var category [{ name: "管控", value: 2500 }, { name: "集中式", value: 8000 }, { name: "纳管", value: 3000 }, { name: "纳管", value: 3000 }, { name: "纳管", value: 3000 } ]; // 类别 var total 10000; // 数据…...
标准IO与系统IO
概念区别 标准IO:(libc提供) fopen fread fwrite 系统IO:(linux系统提供) open read write 操作效率 因为内存与磁盘的执行效率不同 系统IO: 把数据从内存直接写到磁盘上 标准IOÿ…...
【conda】Conda 环境迁移指南:如何更改 envs_dirs 和 pkgs_dirs 以及跨盘迁移
目录 迁移概述一、conda 配置文件1.1 安装 Conda 后的默认目录设置1.2 查看当前 .condarc 配置 二、更改 Conda 的 envs_dirs 和 pkgs_dirs 设置2.1 使用 conda config 命令Windows 和 Linux 系统 2.2 手动编辑 .condarc 文件Windows 系统Linux 系统 2.3 验证设置 三、迁移 Con…...
脏页写入磁盘的过程详解
脏页写入磁盘的过程 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了保证数据的一致性和持久性,数据库系统需要在适当的时候将脏页写入磁盘。了解脏页写入磁盘的过程对于理解数据库的内部工作机制和优化性能至关重要。 二、触发脏页写入的条件…...

数据结构——单链表实现和注释浅解
关于单链表的基础部分增删查改的实现和一点理解,写在注释里~ SList.h #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h>//定义节点的结构 //数据 指向下一个节点的指针 typedef int SLTDataType;typedef struct SListNo…...

滑动窗口系列(同向双指针)/9.7
新的解题思路 一、三数之和的多种可能 给定一个整数数组 arr ,以及一个整数 target 作为目标值,返回满足 i < j < k 且 arr[i] arr[j] arr[k] target 的元组 i, j, k 的数量。 由于结果会非常大,请返回 109 7 的模。 输入&…...
C# 窗体中Control以及Invalidate,Update,Refresh三种重绘方法的区别
在 C# 中,Control 类是 Windows Forms 应用程序中所有控件的基类。它提供了控件的基本功能和属性,这些功能和属性被所有继承自 Control 类的子类所共享。这意味着 Control 类是构建 Windows Forms 应用程序中用户界面元素的基础。 以下是 Control 类的一…...

缓存类型以及读写策略
缓存(Cache)是一种高效的数据存储技术,旨在提高数据访问速度。 它将频繁访问或最近使用的数据临时存储在更快速但较小的存储介质(如内存)中,以减少从较慢的存储设备(如硬盘或远程服务器&#x…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...