七大排序(Java)
目录
一、插入排序
1. 直接插入排序
2. 希尔排序
二、选择排序
1. 直接选择排序
2. 堆排序
三、交换排序
1. 冒泡排序
2. 快速排序
四、归并排序
五、总结
一、插入排序
1. 直接插入排序
抓一张牌,在有序的牌中,找到合适的位置并且插入。
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 稳定性:稳定

代码:
public static void insertSort(long[] array) {for (int i = 1; i < array.length; i++) {//认为第一个数已经有序,所以循环 n - 1 次long tmp = array[i];int j = i - 1;for(; j >= 0; j--) {if (array[j] > tmp) {array[j + 1] = array[j];} else {break;}}//j回退到了 小于0 的地方array[j + 1] = tmp;}}
2. 希尔排序
插入排序的升级版本,即进行大量的分组插排。
- 时间复杂度:O(n^1.3 ~ n^1.5)
- 空间复杂度:O(1)
- 稳定性:不稳定

代码:
//gap:组数public static void shell (int[] array, int gap) {for (int i = gap; i < array.length; i++) {int tmp = array[i];int j = i - gap;for (; j >= 0; j = j - gap) {if (array[j] > tmp) {array[j + gap] = array[j];} else {break;}}array[j + gap] = tmp;}}public static void shellSort(int[] array) {int gap = array.length;while (gap > 1) {shell(array,gap);gap = gap / 2;}shell(array, 1);}
二、选择排序
1. 直接选择排序
找到无序区间中最小的元素的下标,然后将该元素放到无序区间的开始(有序区间的最后)。
- 时间复杂度:O(n^2)
- 空间复杂度:O(1)
- 稳定性:不稳定

代码:
// array: 待排序区间public static void selectSort(int[] array) {for (int i = 0; i < array.length; i++) {int minIdx = i;for (int j = i + 1; j < array.length; j++) {if (array[j] < array[i]) {minIdx = j;}}swap(array, minIdx, i);}}
2. 堆排序
选择排序的升级版本。将无序区间维护成一个大堆(因为从小到达排序,需要大堆)。利用大堆,从无序区间中找到最大值,交换。
- 时间复杂度:O( N*log(N))
- 空间复杂度:O(1)
- 稳定性:不稳定

代码:
//堆排序public static void heapSort(int[] array) {//1.建堆 O(n)creatHeap(array);int end = array.length - 1;//2.交换然后调整 O(n * log(n))while (end > 0) {swap(array, 0, end);shiftDown(array, 0, end);end--;}}public static void creatHeap(int[] array) {for (int parent = (array.length - 1 - 1)/ 2; parent >= 0; parent--) {shiftDown(array, parent, array.length);}}public static void shiftDown(int[] array, int parent, int len) {int child = 2 * parent + 1; //左孩子下标while (child < len) {if (child + 1 < len && array[child] < array[child + 1]) {child++;}//child 下标为左右孩子中最大的孩子的下标if (array[child] > array[parent]) {swap(array, parent, child);parent = child;child = 2 * parent + 1;} else {break;}}}
三、交换排序
1. 冒泡排序
从前往后,两两元素进行比较,前者大于后者则交换。每次循环完一个元素,后面的有序区间就多加一个元素。
- 时间复杂度:O(N^2)
- 有序情况下:O(n)
- 空间复杂度:O(1)
- 稳定性:稳定

代码:
public static void bubbleSort(int[] array) {for (int i = 0; i < array.length - 1; i++) {boolean flag = false;for (int j = 0; j <array.length - 1 - i; j++) {if (array[j + 1] < array[j]) {swap(array, j, j + 1);flag = true;}}if (flag == false) {break;}}}
2. 快速排序
①在待排序区间内,选择一个基准值(pivot),本次代码中选择的是最右边;
②对待排序区间进行 partition 操作,目标:将待排序区间分开,左边的小于等于pivot,右边的大于等于pivot;
③分别再对左右两个小区间按照相同的方式进行处理。
- 时间复杂度:
- 最好【每次可以均匀的分割待排序序列】:O(N*log(N))
- 最坏:数据有序 或者逆序的情况 O(N^2)
- 空间复杂度:
- 最好:O(logN)
- 最坏:O(n) 单分支的一棵树
- 稳定性:不稳定

代码:
public static void quickSort(int[] array) {quick(array, 0, array.length - 1);}public static void quick(int[] array, int left, int right) {if (left >= right) {return;}int pivot = partition(array, left, right);quick(array, left, pivot - 1);quick(array, pivot + 1, right);}//挖坑法public static int partition(int[] array, int start, int end) {int tmp = array[start];while (start < end) {while(start < end && array[end] >= tmp) {end--;}//end位置的元素小于基准值,挖坑array[start] = array[end];while(start < end && array[start] <= tmp) {start++;}//start位置的元素大于基准值,挖坑array[end] = array[start];}array[start] = tmp;return start;}
由于用到了递归,当基准值左右边已经有序时,还需要栈空间来进行递归,所以当数据过大时,可能会导致栈溢出的情况,所以要将快速排序进行优化。
- 当待排序区间元素个数小于某个范围时,可以使用插入排序。
- 找基准值时,采用三数取中法。
代码:
public static void quickSort(int[] array) {quick(array, 0, array.length - 1);}public static void quick(int[] array, int left, int right) {if (left >= right) {return;}//优化1:元素小于某个区间时,使用插入排序if (right - left + 1 < 1400) {insertSort(array, left, right);}//优化2:三数取中法int MinIdx = FindMinIdx(array, left, right);swap(array, MinIdx, left);int pivot = partition(array, left, right);quick(array, left, pivot - 1);quick(array, pivot + 1, right);}//挖坑法public static int partition(int[] array, int start, int end) {int tmp = array[start];while (start < end) {while(start < end && array[end] >= tmp) {end--;}//end位置的元素小于基准值,挖坑array[start] = array[end];while(start < end && array[start] <= tmp) {start++;}//start位置的元素大于基准值,挖坑array[end] = array[start];}array[start] = tmp;return start;}//插入排序public static void insertSort(int[] array, int start, int end) {for (int i = 1; i < end; i++) {int tmp = array[i];int j = i - 1;for (; j >= start; j--) {if (array[j] > tmp) {array[j + 1] = array[j];} else {//array[j + 1] = tmpbreak;}}// j 回退到了小于 0 的位置//或者从 break 出来array[j + 1] = tmp;}}//三数取中法private static int FindMinIdx(int[] array, int start, int end) {int mid = start + ((end - start) >>> 1);if (array[start] < array[end]) {if (array[mid] < array[start]) {return start;} else if (array[mid] > array[end]) {return end;} else {return mid;}} else {if (array[mid] > array[start]) {return start;} else if (array[mid] < array[end]) {return end;} else {return mid;}}}public static void swap(int[] array, int p, int q) {int tmp = array[p];array[p] = array[q];array[q] = tmp;}
快速排序非递归版本:利用栈存储 left 和 right 的值。
public static void quickSort非递归(int[] array) {Deque<Integer> stack = new LinkedList<>();int left = 0;int right = array.length - 1;int pivot = partition(array, left, right);if (pivot > left + 1) {//左边有两位数stack.push(left);stack.push(pivot - 1);}if (pivot < right - 1) {stack.push(pivot + 1);stack.push(right);}while(!stack.isEmpty()) {right = stack.pop();left = stack.pop();pivot = partition(array, left, right);if (pivot > left + 1) {//左边有两位数stack.push(left);stack.push(pivot - 1);}if (pivot < right - 1) {stack.push(pivot + 1);stack.push(right);}}}
四、归并排序
归并排序是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
- 时间复杂度:O(N*log(N))
- 空间复杂度:O(n)
- 稳定性:稳定

在写归并排序代码之前,需要先会写:两个有序数组合并为一个有序数组。
代码:
//将两个有序数组合并为一个有序数组//array1 和 array2 均为有序数组public static int[] mergeArray(int[] array1, int[] array2) {int[] tmp = new int[array1.length + array2.length];int s1 = 0;int s2 = 0;int e1 = array1.length - 1;int e2 = array2.length - 1;int k = 0;while (s1 <= e1 && s2 <= e2){if (array1[s1] <= array2[s2]) {tmp[k++] = array1[s1++];//k++;//s1++;} else {tmp[k++] = array2[s2++];}}while (s1 <= e1) {tmp[k++] = array1[s1++];}while (s2 <= e2) {tmp[k++] = array2[s2++];}return tmp;}
归并排序代码:
public static void mergeSort(int[] array) {mergeSortInternal(array, 0, array.length - 1);}private static void mergeSortInternal(int[] array, int low, int high) {if (low >= high) {return;}int mid = low + ((high - low) >>> 1);mergeSortInternal(array, low, mid);mergeSortInternal(array, mid + 1, high);merge(array, low, mid, high);}public static void merge(int[] array, int low, int mid, int high) {int[] tmp = new int[high - low + 1];int k = 0;int s1 = low;int e1 = mid;int s2 = mid + 1;int e2 = high;while (s1 <= e1 && s2 <= e2) {if (array[s1] <= array[s2]) {tmp[k++] = array[s1++];} else {tmp[k++] = array[s2++];}}while (s1 <= e1) {tmp[k++] = array[s1++];}while (s2 <= e2) {tmp[k++] = array[s2++];}//普通的归并数组需要直接返回 tmp 数组//但是在归并排序中,要将 tmp 数组重新拷贝到 array 数组中,//并且考虑在右子树中合并时,不能覆盖左边已经合并好的元素for (int i = 0; i < k; i++) {array[low + i] = tmp[i];}}
非递归版本:
public static void mergeSort非递归(int[] array) {int nums = 1; //每组的数据个数while (nums < array.length) {for (int i = 0; i < array.length; i++) {int left = i;int mid = left + nums - 1;//防止越界if (mid >= array.length) {mid = array.length - 1;}int right = mid + nums;//防止越界if (right >= array.length) {right = array.length - 1;}//下标确定之后进行合并merge(array, left, mid, right);}nums *= 2;}}
五、总结
七大排序中:
稳定的排序:冒泡排序、插入排序、归并排序
插入排序主要看数组是否有序,来影响其时间复杂度
归并排序无论什么情况下,时间复杂度都为 O(N*log(N))
时间复杂度为O(N*log(N))的排序:快速排序、堆排序、归并排序
要想速度快就选 快速排序
要想稳定就选 归并
要想空间复杂度低就选 堆排序
| 排序 | 时间复杂度 | 空间复杂度 | 稳定性 |
| 插入排序 | O(N^2) | O(1) | 稳定 |
| 希尔排序 | O(N^1.3) | O(1) | 不稳定 |
| 选择排序 | O(N^2) | O(1) | 不稳定 |
| 堆排序 | O(N*log(N)) | O(1) | 不稳定 |
| 冒泡排序 | O(N^2) | O(1) | 稳定 |
| 快速排序 | O(N*log(N)) | O(log(N)) | 不稳定 |
| 归并排序 | O(N*log(N)) | O(n) | 稳定 |
相关文章:
七大排序(Java)
目录 一、插入排序 1. 直接插入排序 2. 希尔排序 二、选择排序 1. 直接选择排序 2. 堆排序 三、交换排序 1. 冒泡排序 2. 快速排序 四、归并排序 五、总结 一、插入排序 1. 直接插入排序 抓一张牌,在有序的牌中,找到合适的位置并且插入。 时间…...
分享一些可以快速掌握python语法的小技巧
下面是我总结的一些有助于快速掌握 Python 语法的小技巧,欢迎一起交流。 注释:在代码中添加注释可以帮助你和其他人理解代码的目的和功能。在 Python 中,使用 # 符号来添加单行注释,使用三引号 """ 或 来添加多行…...
1.FFmpeg-音视频基础
专栏介绍基于最新的FFmpeg5.1.2版本讲解学习, 跟随博主一起学习ffmpeg: 本专栏学习流程为: FFmpeg安装、...
Parasoft的自动化测试平台到底强在哪?
在如今产品迭代如此之快的大背景下,软件测试这项工作越来越被大家所重视,但是通常情况下大家都是选择在产品上线前再去做测试,这个时候就会面临很多麻烦和挑战。首先,产品已经开发好之后,体量比较大,要从哪…...
FastDDS-0.简介
FastDDS简介 eProsima Fast DDS 是 DDS (Data Distribution Service) 协议的一个C语言实现版本,该协议由 Object Management Group (OMG) 组织定义。 eProsima Fast DDS 库既提供了一个应用编程接口(API),又提供了一种通信协议&a…...
Flutter入门进阶之旅 -开源Flutter项目
开源Flutter项目 该项目为纯flutter端项目,采用aar方式寄生在原生APP中,作为APP中的一个独立模块 在业务逻辑上做到与原生APP完全隔离,Flutter端开发者,可完全不用关注原生端的业务模块 两端开发彼此业务隔离,缩小了对…...
Opencv项目实战:21 美国ASL手势识别
0、项目介绍 首先,我可以保证在这里,你并不需要多么了解深的机器学习算法,我的初衷是通过本项目,激发大家学习机器学习的动力。选择这种手势原因是因为只有24个字母,你的电脑足以带的动,虽然我只训练A、B、…...
强化学习RL 01: Reinforcement Learning 基础
目录 RL理解要点 1. RL数学基础 1.1 Random Variable 随机变量 1.2 概率密度函数 Probability Density Function(PDF) 1.3 期望 Expectation 1.4 随机抽样 Random Sampling 2. RL术语 Terminologies 2.1 agent、state 和 action 2.2 策略 policy π 2.3 奖励 reward …...
C语言之练习题合集
💗 💗 博客:小怡同学 💗 💗 个人简介:编程小萌新 💗 💗 如果博客对大家有用的话,请点赞关注再收藏 🌞 文章目录leetcode 题号:728. 自除数leetcode 题号:238.…...
sublimeText3新建文件自动添加注释头
参考: https://github.com/shiyanhui/FileHeader/blob/master/README.rst https://packagecontrol.io/packages/FileHeader https://github.com/shiyanhui/FileHeader fileheader:https://codeload.github.com/shiyanhui/FileHeader/zip/refs/heads/m…...
AndroidStudio打包HBuilderX的H5+项目为安卓App【一次过,无任何异常报错】
目录 1.查看HBuilderX的版本号 2.下载Dcloud上对应的安卓SDK 3.下载完安卓SDK后,我们解压它,注意不要放在任何有中文组成的文件夹中【是否有中文决定于你鼠标单击上面路径后,第一张图还没鼠标单击,第二张已鼠标单击,…...
【Linux】进程概念
目录 一、基本概念 二、查看进程 三、系统调用获取进程标示符 1、获取自己的PID 2、获取父进程的PID 四、创建进程 1、初识fork 2、使用fork的方式 五、进程状态 1、阻塞 2、挂起 3、R状态 4、S状态 5、D状态 6、T状态 6.1、kill指令 6.2、暂停进程与继续进程 …...
使用pyinstaller库打包exe时显示KeyError怎么办
PyInstaller是一个Python库,用于将Python应用程序转换为独立的可执行文件(executable)文件,支持多平台。它可以将Python解释器、依赖的库和脚本打包成一个单独的可执行文件,从而使应用程序可以独立运行,而无…...
k8s新增节点机器,无法拉取和推送镜像的解决方案
1、首先检查配置,查看镜像仓库是否已授权,若无授权,则进行授权。 命令:cat /etc/systemd/system/docker.service.d/docker-options.conf内容如果有这样一句就是已经授权,如果没有,就需要把这句加进去&…...
测试报告踩坑的点
测试报告作为测试人员的核心输出项,是体现自己工作价值的重要承载工具,需要我们认真对待,所以我们要重视测试报告的输出,那么在编写测试报告的时候,我们有哪些点需要注意的呢? 01 不要乱用模板 很多测试新人在编写测试…...
【Java】创建多线程的四种方式
一、方式1:继承Thread类 步骤: 创建一个继承于Thread类的子类重写Thread类的run()方法 ----> 此线程执行的操作声明在方法体中创建当前Thread子类的对象通过实例对象调用start()方法,启动线程 ----> Java虚拟机会调用run()方法 注意…...
【数据结构】队列的接口实现(附图解和源码)
队列的接口实现(附图解和源码) 文章目录队列的接口实现(附图解和源码)前言一、定义结构体二、接口实现(附图解源码)1.初始化队列2.销毁队列3.队尾入队列4.判断队列是否为空5.队头出队列6.获取队列头部元素7…...
日本知名动画公司东映动画加入 The Sandbox 元宇宙
与 Minto 合作将东映动画的 IP 呈现在元宇宙。 The Sandbox 很荣幸能与东映动画合作,与 Minto 携手在 The Sandbox 元宇宙中创建基于东映动画 IP 的相关体验。 作为日本动画的先驱,东映动画制作了日本最大和世界领先的动画作品,包括《龙珠》、…...
QuickHMI Hawk R3 Crack
基于网络的 SCADA / HMI 系统 QuickHMI Hawk R3 QuickHMI是一个 100% 基于网络的SCADA/HMI 系统。 得益于HTML5、SVG和Javascript等现代网络技术,可视化可以在任何当前浏览器和设备中显示。作为浏览器的替代品,可以使用“独立查看器”和移动应用程序。 Q…...
【C语言】寻找隐藏字母游戏
编程实现一个游戏程序,会将连续三个字母中的一个隐去,由玩家填写隐去的那个字母,如屏幕上显示A ? C,则玩家需要输入B;屏幕上显示?B C,则玩家需要输入A。记录玩家完成20次游戏的时间以及正确率。…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
沙箱虚拟化技术虚拟机容器之间的关系详解
问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西,但是如果把三者放在一起,它们之间到底什么关系?又有什么联系呢?我不是很明白!!! 就比如说: 沙箱&#…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
