一文搞定插入排序算法
文章目录
- 三、插入排序
- 1、插入排序原理
- 2、图解插入排序
- 3、插入排序思路
- 4、代码实现插入排序
- 5、时间复杂度分析
- 6、小技巧:常用时间复杂度
- (1) O(1)
- (2) O(n)
- (3) O(n^2)
- (4) O(n^3)
- (5) O(lg n)
- (6) O(n lg n)
- (7) O(2^n)
- 7、附:常用的排序算法的时间复杂度和空间复杂度
三、插入排序
1、插入排序原理
每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置,将该元素插入到有序数列的合适位置中。
插入排序,顾名思义其基本操作就是插入
,不断把一个个元素插入到一个序列中
,最终得到排序序列
。
插入排序就像打牌一样,当你摸到比较小的牌时,通常往后放,遇到比较大的牌时,通常往前方。当然了,还要看自己个人习惯。
在打牌时,我们通常每次从桌子摸一张牌,然后把这张牌再放到一个正确的位置。
为了找到这张牌放置的正确位置,我们从左到右(或者从右到左)进行比较。
2、图解插入排序
第一轮:
i=2
第二个数与前面的数做比较,发现2比5小则把小的往前方,把大的往后放
第二轮:
i+1=3
第二轮时,从第三个数与前面的作比较,发现比5小,把2大,则把5往后移动
第三轮:
i+1=4
第三轮时,因为是i+1,所以这次是第4个数与前面的数作比较,发现自己就是最大的,则不调整位置
第四轮:
i+1=5
第四轮从第5个数开始比较,发现比2小,则放在2的前面,2和后面的都向后移动调整位置。
第五轮:
i+1=6
从第6个数依次向前比较,找到2号(按照数组的索引:0,1,2)位置,则插入此位置,并把后面的依次往后移动。
完成:
3、插入排序思路
如上图所示,此排序需要维护一个数组中的两个列表,可以把插入排序的数组分成已排序和未排序的数组。
排序的过程中只需要维护已排序的部分即可。
每次拿未排序列表的首个数与已排序的列表的数据依次作比较。
找到合适的位置后,移动这些的位置然后插入进来即可完成插入的操作。
步骤:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果被扫描的元素(已排序)大于新元素,将该元素后移一位
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
4、代码实现插入排序
从小到大:
package 排序算法.插入排序;import java.util.Arrays;/*** @Auther: truedei* @Date: 2020 /20-6-6 22:59* @Description:*/
public class InsertionSort {public static int[] INSERTION_SORT(int[] ints){//所有参与排序的数组的索引范围,为什么从1开始呢,因为可以把0号位置的数据当成已经排序好的for (int i = 1; i < ints.length; i++) {//一直到排到的第i个位置结束,进行倒着比较for (int j = i; j >0 ; j--) {//比较,如果符合要求则交换位置if(ints[j] < ints[j-1]){int temp = ints[j];ints[j]=ints[j-1];ints[j-1]=temp;}else {//遇到不符合要求的数据则停止,代表前面都是最小或者最大的了break;}}}return ints;}public static void main(String[] args) {System.out.println(Arrays.toString(INSERTION_SORT(new int[]{2,5,4,7,6,1,3})));}}
结果:
[1, 2, 3, 5, 4, 6, 7]
从大到小:
package 排序算法.插入排序;import java.util.Arrays;/*** @Auther: truedei* @Date: 2020 /20-6-6 22:59* @Description:*/
public class InsertionSort {public static int[] INSERTION_SORT(int[] ints){//所有参与排序的数组的索引范围,为什么从1开始呢,因为可以把0号位置的数据当成已经排序好的for (int i = 1; i < ints.length; i++) {//一直到排到的第i个位置结束,进行倒着比较for (int j = i; j >0 ; j--) {//比较,如果符合要求则交换位置if(ints[j] > ints[j-1]){int temp = ints[j];ints[j]=ints[j-1];ints[j-1]=temp;}else {//遇到不符合要求的数据则停止,代表前面都是最小或者最大的了break;}}}return ints;}public static void main(String[] args) {System.out.println(Arrays.toString(INSERTION_SORT(new int[]{2,5,4,7,6,1,3})));}}
结果:
[7, 6, 5, 4, 3, 2, 1]
[7, 6, 5, 4, 3, 2, 1]
5、时间复杂度分析
插入排序使用了双层for循环
,其中内层循环体是真正完成排序的代码,所以我们分析插入排序的时间复杂度时忽略其他的,主要分析一下内层循环体的时间复杂度即可;
可以注意到该算法就两个操作是有用的:
- 一个是
比较
数据 - 一个是
交换
数据
最坏的情况:
比较数据次数:
最坏的情况就是从头到尾进行比较
(N−1)+(N−2)+(N−3)+...+2+1=((N−1)+1)×N−12=N22−N2(N-1)+(N-2)+(N-3)+...+2+1=((N-1)+1)×\frac {N-1}{2}=\frac{N^{2}}{2}-\frac{N}{2} (N−1)+(N−2)+(N−3)+...+2+1=((N−1)+1)×2N−1=2N2−2N
交换数据次数:
最坏的情况就是从头到尾进行交换
(N−1)+(N−2)+(N−3)+...+2+1=((N−1)+1)×N−12=N22−N2(N-1)+(N-2)+(N-3)+...+2+1=((N-1)+1)×\frac {N-1}{2}=\frac{N^{2}}{2}-\frac{N}{2} (N−1)+(N−2)+(N−3)+...+2+1=((N−1)+1)×2N−1=2N2−2N
时间复杂度就是:
(N22−N2)+(N22−N2)=N2−N(\frac{N^{2}}{2}-\frac{N}{2})+(\frac{N^{2}}{2}-\frac{N}{2})=N^{2}-N (2N2−2N)+(2N2−2N)=N2−N
根据大O推导法则,保留最高阶项:
去掉常数项还剩下:
N2N^{2} N2
所以最终得出时间复杂度为:
O(N2)O(N^{2}) O(N2)
6、小技巧:常用时间复杂度
(1) O(1)
(1)O(1) 这个针对的是常数;对于一个N,不管这个N是如何增长,这个时间是不变的。
例如下面这些代码的时间复杂度都是O(1):
/*** @Auther: truedei* @Date: 2020 /20-6-2 22:01* @Description:*/
public class Test {public static void main(String[] args) {System.out.println("你好,我叫郑晖");System.out.println("你好,我叫郑晖");System.out.println("你好,我叫郑晖");System.out.println("你好,我叫郑晖");}}
还有这种:
我有一个数组,我知道了我需要的这个数据所在的索引,然后去拿这个值,咋这种也是O(1)
/*** @Auther: truedei* @Date: 2020 /20-6-2 22:01* @Description:*/
public class Test {public static void main(String[] args) {String[] names = {"小明","小红","郑晖"};System.out.println("你好,我叫"+names[2]);}}
(2) O(n)
O(n)是一个线性增长的。
经常用在for()循环当中
例如下面这种代码:
/*** @Auther: truedei* @Date: 2020 /20-6-2 22:01* @Description:*/
public class Test {public static void main(String[] args) {String[] names = {"小明","小红","郑晖"};for (int i = 0; i < names.length; i++) {System.out.println("你好,我叫"+names[i]);}}}
(3) O(n^2)
是一个平方级的的增长。经常出现在两层for循环
。
例如本文所写的:
public static int[] sort(int A[]){for (int i = 0; i < A.length; i++) {for (int j = 0; j < A.length -i - 1 ; j++) {.....}}return A;
}
(4) O(n^3)
是一个立方级的增长。经常出现在遍历一个三层的for循环
中
for (...) {for (...) {for (...) {.....}}}
(5) O(lg n)
是一个对数级。
在二分查找法里就是O(lg n)
。
每次执行N是以一个倍数的形式是递减的:
比如第1次:1/2
比如第2次:1/4
比如第3次:1/8
比如第4次:1/16
…
快速的让N的规模变小。
(6) O(n lg n)
在排序中经常见到的
(7) O(2^n)
指数级的
7、附:常用的排序算法的时间复杂度和空间复杂度
排序法 | 最差时间分析 | 平均时间复杂度 | 稳定度 | 空间复杂度 |
---|---|---|---|---|
冒泡排序 | O(n^2) | O(n^2) | 稳定 | O(1) |
快速排序 | O(n^2) | O(n*log2n) | 不稳定 | O(log2n)~O(n) |
选择排序 | O(n^2) | O(n^2) | 不稳定 | O(1) |
二叉树排序 | O(n^2) | O(n*log2n) | 不一顶 | O(n) |
插入排序 | O(n^2) | O(n^2) | 稳定 | O(1) |
堆排序 | O(n*log2n) | O(n*log2n) | 不稳定 | O(1) |
希尔排序 | O | O | 不稳定 | O(1) |
如果对你有帮助,可以分享给你身边的朋友。或者给俺点个大大的赞和大大的评论,点赞和评论就是给我最大的支持,感谢。
水平有限,难免会有疏漏或者书写不合理的地方,欢迎交流讨论。
作者:TrueDei
作者唯一博客CSDN:https://truedei.blog.csdn.net/
转载说明:如需转载请注明原地址和作者名。
如果喜欢我的文章,还没看够可以关注我,我会用心写好每一篇文章。
欢迎大佬们加入在下的小社区:
一文搞定插入排序算法相关推荐
- 一文搞定Diff算法
关注公众号"执鸢者",回复"资料"获取500G资料(各"兵种"均有),还有专业交流群等你一起来潇洒.(哈哈) 不管是Vue还是React,其 ...
- 一文搞定面试中的二叉树问题
一文搞定面试中的二叉树问题 版权所有,转载请注明出处,谢谢! http://blog.csdn.net/walkinginthewind/article/details/7518888 树是一种比较重 ...
- 【语义分割】综述——一文搞定语义分割
本文记录了博主阅读的关于语义分割(Semantic Segmentation)的综述类文章的笔记,更新于2019.02.19. [语义分割]综述--一文搞定语义分割 参考文献网址 An overvie ...
- php带参数单元测试_一文搞定单元测试核心概念
基础概念 单元测试(unittesting),是指对软件中的最小可测试单元进行检查和验证,这里的最小可测试单元通常是指函数或者类.单元测试是即所谓的白盒测试,一般由开发人员负责测试,因为开发人员知道被 ...
- 【Python基础】一文搞定pandas的数据合并
作者:来源于读者投稿 出品:Python数据之道 一文搞定pandas的数据合并 在实际处理数据业务需求中,我们经常会遇到这样的需求:将多个表连接起来再进行数据的处理和分析,类似SQL中的连接查询功能 ...
- 【面试锦囊】14种模式搞定面试算法编程题(8-14)
面试锦囊之知识整理系列 面试锦囊系列一直有收到大家的反馈,包括后台内推成功的消息.朋友的同事从创业小公司成功跳到huawei等等,非常高兴小破号的这些整理分享能够真正地帮助到大家,以后也会继续.为了更 ...
- 一文搞定Swing和Qt按钮和文本框的创建
一文搞定Swing和Qt按钮和文本框的创建 Qt的截图 java的 源码 package com.lujun;import java.awt.Container;import javax.swing. ...
- 一文搞定C#关于NPOI类库的使用读写Excel以及io流文件的写出
一文搞定C#关于NPOI类库的使用读写Excel以及io流文件的写出 今天我们使用NPOI类库读写xlsx文件, 最终实现的效果如图所示 从太平洋官网下载相应的类库,大概4~5MB,不要从github ...
- 一文搞定Qt读写excel以及qt读写xml数据
一文搞定Qt读写excel以及qt读写xml数据 最终的实现效果图 RC_ICONS = logo.ico .pro文件同级目录下加入 logo.ico 图标文件,运行文件,文件的图标就被写入软件 u ...
最新文章
- VS Code 安装 Go 插件、自定义扩展配置、断点调试
- 33.搜索插件——autocomplete
- 关于bcp的那些事儿
- PHP-四种解析XML文件的方法
- java怎么给类中的私有变量赋值_Java核心技术笔记分享------第二章 类与对象
- .NetCoreLinuxDockerPortainer踩坑历险记
- 开源纯C#工控网关+组态软件(三)加入一个新驱动:西门子S7
- leetcode-114-二叉树展开为链表*
- AliOS Things声源定位应用演示
- 不允许输入特殊字符的正则表达式_JavaScript正则表达式常用技巧
- 《scikit-learn》SVM(二)数据不均衡
- 用Alamofire进行网络请求的一段代码解析(一)
- 这个好,精英们的自由时间都用来干嘛?
- socket网络字节序以及大端序小端序
- python参考手册 第二章
- 爬取豆瓣电影top250
- 【AI数学原理】函数求导(精髓篇)
- 交通灯keil程序加2位数码管_51单片机红绿灯两个数码管显示实验报告
- reactos操作系统实现 1
- 黑苹果入门:必备工具篇
热门文章
- 天龙八部TLBB系列 - 网单服务端Public/Data目录文件说明
- MS切面时surface mesh设置小数提示错误解决方案
- 自动驾驶汽车测试技术与应用进展
- 《NLTK基础教程》读书笔记 006期
- 9017R单节锂电池线性充电管理 IC
- SpringBoot集成支付宝沙箱手机网站支付详细流程和踩坑分享
- java + nginx + ffmpeg + vue实现摄像头,rtmp、rtsp直播流协议的实时播放
- 求生之路2不显示局域网服务器,【求生之路2怎么局域网联机】如何局域网联机_求生之路2局域网联机教程_游戏城...
- Java空指针异常处理
- unity之万代南梦宫高管:传统开发商如何做好手游