Java温故而知新-插入排序
插入排序
插入排序的基本思想是将待排序的元素依次插入序列合适的位置,然后将这个位置后面的元素依次向后移动一位
位置1 2 3 4 5 6
序列5 4 2 1 8 3
设第1位为最初始的基础元素,也就是5,待排元素就是4,此时逻辑顺序是5|4 2 1 8 3(用“|”来表示排序到哪个位置了)
那么第一趟排序下来后,
序列变成:45|2183。
待排元素就是2,第2趟后,245|183
待排元素就是1,第3趟后,1245|83
待排元素就是8,第4趟后,12458|3
待排元素就是3,第5趟后,123458|
这样就排序成功了。
上面就是插入排序,数学逻辑上非常清晰,序列可以分为两个区,有序区和混乱区。第一步,我们要做的就是每次从混乱区取出一个混乱元素插入到有序区的序列排布中,那么如何插入呢?就要看第二步的内容了。
第一步如何取出元素呢?显然是要将每个元素(除去预置的那个)都取出一遍,那么用个for循环遍历整个序列就行。
伪代码
for(int i = 1;i < arr.length;i++){
temp = arr[i];
}
第二步,执行插入步骤,这一步需要做两个事情,1寻找合适的位置,2插入后将其他元素往后移动一位
(1)如何寻找合适的位置呢?
有序区的元素默认都是从小到大排列的,都是有顺序的,那么就好办了,只要找到合适的位置就行,然后移动后面元素的位置就行。
例如
序列 12458|3
3先和1比较,不合适;
3再和2比较,不合适;
3再和4比较,合适,找到位置了。
3再和2比较,2小,不符合要求,不挪动;
3再和1比较,1小,不符合要求,不挪动;
实现这个逻辑最简单就是用一个for循环,设置一个条件和边界,去遍历一遍。
(2)接下来处理一个问题就是讲元素往后挪动一位。
既然我们已经找到这个边界了,那么只需要把这个边界后面的元素依次往后挪动一位就可以了。
这里就又是一个for循环,边界是“合适位置+1”到“当前待排元素的位置”。
所以这个排序就是一个for循环里面嵌入两个for循环
下面是伪代码
for(){//处理所有元素的遍历
temp = 待处理的元素
for(){//这个循环用来寻找合适的位置
}
for(){//这个循环用来将那些元素依次向后挪动
}
}
这样确实可以实现,算法时间复杂度可以算做O(n^2),但是用两个for循环在里面,写起来有些冗长有没有更好的解决办法呢?将编写的复杂度下降一些呢?
解决办法就是在寻找合适位置这一步时,从后往前遍历,每对比到一个不合适的元素,就把这个元素往后挪动一位。
例如
序列 12458|3
temp = 3;
3先和8比较,不合适,挪动后1245 8;
3再和2比较,不合适,挪动后124 58;
3再和4比较,合适,找到位置了,挪动后123458;
3再和2比较,2小,不符合要求,不挪动;
3再和1比较,1小,不符合要求,不挪动;
这样边比较边挪动的做法,可以将寻找位置和挪动元素的操作结合起来,放到一个遍历循环中。
下面就不赘述了,放源码。
package com.chapter.five;
/**
* 需求 直接插入排序法
* 思路 1将一个数组,分成两个区,一个是有序区,一个是无序区
* 2每次取出无序区的一个元素,到有序区排序
* 3排序的原则是待排元素依次与有序区元素进行比较,插入到合适地方
* 4插入时,待排元素放在该位置,后面的元素依次向后移一位
* 排成从小到大
* @author huxingyue
*
*/
class InsertSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
InsertSort insert = new InsertSort();
int[] arr = new int[]{10,1,9,2,8,3,7,4,6,5};
System.out.print("数组排序前是:");
for(int i:arr){
System.out.print(i+" ");
}
// insert.funLowToHigh(arr);
insert.funHighToLow(arr);
System.out.print("数组排序后是:");
for(int i:arr){
System.out.print(i+" ");
}
}
void funLowToHigh(int[] arr){ //这个插入排序是从小到大的
int temp; //用于存放临时元素
for(int i = 1;i < arr.length;i++){
temp = arr[i];//设temp为取出的待排混乱元素
int j =0;
for(j = i-1 ; j >= 0 && temp < arr[j];j--){
arr[j+1] = arr[j]; //如果临时值与对比元素相比,临时值小,那对比元素就往后移动一位
}
arr[j+1] = temp; // 这一步j已经自减1了
}
}
void funHighToLow(int[] arr){ //这个插入排序是从大到小的
int temp;
for(int i = 1;i < arr.length;i++){
temp = arr[i];
int j = 0;
for(j = i-1;j >= 0 && temp > arr[j];j--){
arr[j+1] = arr[j]; //如果临时值与对比元素相比,临时值大,那对比元素就往后移动一位
}
arr[j+1] = temp; // 这一步j已经自减1了
}
}
}
写在最后,讲一讲个人对插入排序的理解。
本质上来讲,插入排序和冒泡排序都属于一类排序,即比较相邻两个数,然后操作相邻数的一个过程。
如果一个序列中有两个数,a1和a2,且a1>a2,则命名为一个比较对,插入排序的算法和比较对的数量有关系,因为仅仅存在一个比较对的时候,才会进行操作,数据向后移动,也就是说,忽略验证内层循环条件的时间,那么确定了比较对的数量,插入排序的时间复杂度变成了一个一元线性的函数,设序列中有9个比较对,序列长度为n,那么总时间就是9n,而不是我们通常意味的n*n。
关于上面的描述很潦草,具体权威的描述可以参考《数据结构与算法java版》作者Mark Allen Weiss中,关于插入排序的解读,醍醐灌顶值得一看。
如果想改善这种算法的性能几乎不大可能,因为他总是比较相邻的元素,如果想提高性能,就要比较相隔远一点的元素,然后再操作,可以参考希尔排序。或者使用全新的排序方法,例如快速排序。
Java温故而知新-插入排序的更多相关文章
- Java温故而知新-杨辉三角形
Java温故而知新-杨辉三角形 一. 先说需求 需求 打印输出杨辉三角形,行数可变,支持50行内的任意数. 预期结果如图所示 1 这是第几行呢,是第1 1 1 这是第几行呢,是第2 1 2 1 这是第 ...
- 疯狂的Java算法——插入排序,归并排序以及并行归并排序
从古至今的难题 在IT届有一道百算不厌其烦的题,俗称排序.不管是你参加BAT等高端笔试,亦或是藏匿于街头小巷的草根笔试,都会经常见到这样一道百年难得一解的问题. 今天LZ有幸与各位分享一下算法届的草根 ...
- JAVA排序--[插入排序]
package com.array; public class Sort_Insert { /* * 项目名称:插入排序 ; * 项目要求:用JAVA对数组进行排序,并运用插入排序算法; * 作者:S ...
- Java直接插入排序
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入. 算法步骤: 1)将第一待排序序列第一个元素看做一个有序序列,把第二 ...
- 【Java SE】如何用Java实现插入排序
摘要:前面三期分别写了三篇简单排序的算法,今天来讲一点稍微难一点的排序算法-----插入排序. 基本思想: 设n个数据已经按照顺序排列好(假定从小排到大). 输入一个数据x,将其放在恰当的位置,使其顺 ...
- JAVA数据结构--插入排序
插入排序(英语:Insertion Sort)是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入.插入排序在实现上,通常采用in- ...
- Java实现插入排序
package Sort; import java.util.Arrays; public class InsertionSort { public static int[] sort(int[] l ...
- java 用插入排序思想,对不规则数组排序。
知道插入排序后,无意中发现,用插入排序思想,对不规则数组排序的排序 发现和许多大神写的不一样,大神写的简洁多了.--------
- Java算法-插入排序
插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经排好序,本趟需要找到 i 对应的元素 x 的正确位置 k ,并且在寻找这个位置 k 的过程中逐个将比较过的 ...
随机推荐
- hdu_1907:John(Nim变形)
题目链接 仍是取石子,不过取到最后一个的败 参考链接:http://www.voidcn.com/blog/liwen_7/article/p-3341825.html 简单一句话就是T2 S0必败 ...
- 安装 Docker Machine - 每天5分钟玩转 Docker 容器技术(45)
前面我们的实验环境中只有一个 docker host,所有的容器都是运行在这一个 host 上的.但在真正的环境中会有多个 host,容器在这些 host 中启动.运行.停止和销毁,相关容器会通过网络 ...
- [luogu P1967][NOIp2013] 货车运输
题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多 ...
- HDU 6034---Balala Power!(搜索+贪心)
题目链接 Problem Description Talented Mr.Tang has n strings consisting of only lower case characters. He ...
- Unity Shader入门教程(二)最基本的Diffuse和Normal样例
本教程参考了<猫都能学会的Unity3dShaderLab教程.CHM>, 1.请上网搜索并下载此文件. 2.随后再下载里面提到的素材: http://vdisk.weibo.com/s/ ...
- Intellij IDEA 2017 详细图文教程之概述
天天编码 , 版权所有丨本文标题:Intellij IDEA 2017 详细图文教程之概述 转载请保留页面地址:http://www.tiantianbianma.com/intellij-idea- ...
- css3关键帧动画实现轮播效果
实现效果:打开手机京东,可以看到首页的头部,以这个头部为基础,仿写一个类似的样式. 思路:仔细观察可以发现,手机京东的头部是以一个搜索栏和轮播特效组成的,而这个搜索栏是以轮播特效做为背景的,现在运用c ...
- 认识sass和webstrom的sass配置
认识sass和webstrom的sass配置 我纳闷啊!电脑死机,我刚才编写的内容全没了. 呵呵! 一.sass的使用 1.首先要到官网下载个稳定的ruby版本,因为sass运行是需要ruby环境 它 ...
- 抵制克苏恩[Lydsy2017年4月月赛]
题目描述 小Q同学现在沉迷炉石传说不能自拔.他发现一张名为克苏恩的牌很不公平.如果你不玩炉石传说,不必担心,小Q同学会告诉你所有相关的细节.炉石传说是这样的一个游戏,每个玩家拥有一个 30 点血量的英 ...
- overlay 如何实现跨主机通信?- 每天5分钟玩转 Docker 容器技术(52)
上一节我们在 host1 中运行了容器 bbox1,今天将详细讨论 overlay 网络跨主机通信的原理. 在 host2 中运行容器 bbox2: bbox2 IP 为 10.0.0.3,可以直接 ...