七大排序(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次游戏的时间以及正确率。…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
