目录
创作不易,如果本篇博客对您有一定的帮助,大家记得留言+点赞哦。
直接插入排序
概念
直接插入排序是插入排序的一种。把待排序的数字按大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。比如我们玩扑克牌的时候,就用到了此思想。
算法思路
1.从第一个元素开始,该元素默认为已经被排序;
2.取出下一个元素,在已经排序的元素序列中从后往前扫描;
3.如果取出的新元素大于序列中 (已经排好序) 的被扫描元素,将被扫描元素移到下一位置。
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
5.将新元素插到该位置的下一位置(特殊情况 新元素都比已排序元素小)
6.重复步骤2~5。
动画演示
代码如下
public static void insertSort(int[] a){
int i = 0;
int j = 0;
int tmp = 0;
for(i = 1;i<a.length;i++){ //此层循环代表待插入的新元素 从第二个元素开始
tmp = a[i]; //存储新元素,防止被覆盖
j = i-1;
while(j>=0 && a[j] > tmp){
a[j+1] = a[j]; //已排序元素向后移动
j--;
}
if(j==i-1) continue; //说明没有进入while循环,该元素目前是最大的,不用排序
if(j == -1 || (j>=0 && a[j]<=tmp)){ j==-1 //表示该元素目前最小
a[j+1] = tmp;
}
}
}
♣①:首先对于单趟的插入,因为是要将一个数插入到一个有序区间中去,假设区间的最后一个位置为(j),那这个待插入数据的位置就是(j+1),因为插入过程中这个数据存在被覆盖的可能,我们先用一个变量tmp保存起来,
♣②:接着将待插入的数据与有序区间的最后一个数进行比较,因为默认选择升序,遇到比tmp大的数据,需要把a[end]往后挪,然后下标往前走,直到(j<0)或者是在中途比较的过程中发现有比待插入数据还要小或者相等的数,就停止比较,跳出这个循环。随着数据的移动,end后一定会空出一个位置,此时执行a[j + 1] = tmp,就可以实现将待插入数据放入有序系列中,并保持这个序列有序。
复杂度分析
时间复杂度 最好O(n) 最坏O(n^2)
空间复杂度 O(1 ) 只申请了 tmp 一个空间
稳定性 稳定 因为当有两个相同的数字时 后面加入的总在后面
时间复杂度测试
接下来我们试着用大量数据测试一下。
int[] a = new int[10_0000]; //10万个数据测试
1.orderArray函数实现生成一个基本有序数列,即从小到大排列。
public static void orderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
}
2.notOrderArray函数生成一个倒序数列,即从大到小排列。
public static void notOrderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = a.length-i;
}
}
3.randomArray函数生成一个随机无序数列。
public static void randomArray(int[] a) {
Random random = new Random();
for (int i = 0; i < a.length; i++) {
a[i] = random.nextInt(10_0000);
}
}
4.testInsertSort函数测试 System.currentTimeMillis() 返回值单位是毫秒。
public static void testInsertSort(int[] a){
int[] tmpArray = Arrays.copyOf(a,a.length);
long startTime = System.currentTimeMillis(); //注意用long接收
insertSort(tmpArray);
long endTime = System.currentTimeMillis(); //返回单位是毫秒
System.out.println("直接插入排序耗时:"+(endTime-startTime));
}
5.main函数调用执行
public static void main(String[] args) {
int[] a = new int[10_0000];
//有序
System.out.println("基本有序数列");
orderArray(a);
testInsertSort(a);
//倒序
System.out.println("逆序数列");
notOrderArray(a);
testInsertSort(a);
//随机乱序
System.out.println("无序数列");
randomArray(a);
testInsertSort(a);
}
运行结果
完整代码
import java.util.Random;
public class sort {
public static void main(String[] args) {
int[] a = new int[10_0000];
//有序 1 2 3 4 5 ...
System.out.println("基本有序数列");
orderArray(a);
testInsertSort(a);
//逆序 9 8 7 6 5 ...
System.out.println("逆序数列");
notOrderArray(a);
testInsertSort(a);
//乱序
System.out.println("无序数列");
randomArray(a);
testInsertSort(a);
}
//插入排序
//时间复杂度 最好O(n) 最坏O(n^2)
//空间复杂度 O(1) 因为只申请了 tmp 一个空间
//稳定性 稳定 因为当有两个相同的数字时 后面加入的总在后面
public static void insertSort(int[] a) {
int i = 0;
int j = 0;
int tmp = 0;
for(i = 1;i<a.length;i++) {
tmp = a[i];
j = i-1;
while(j>=0 && a[j] > tmp) {
a[j+1] = a[j];
j--;
}
if(j==i-1) continue;
if(j == -1 || (j>=0 && a[j]<=tmp)) {
a[j+1] = tmp;
}
}
}
//生成有序数组 从小到大排列
public static void orderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
}
//n无序 其实就是从大到小排列
public static void notOrderArray(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = a.length-i;
}
}
//乱序 随机生成序列
public static void randomArray(int[] a) {
Random random = new Random();
for (int i = 0; i < a.length; i++) {
a[i] = random.nextInt(10_0000);
}
}
//大量数据测试
public static void testInsertSort(int[] a){
int[] tmpArray = Arrays.copyOf(a,a.length);
long startTime = System.currentTimeMillis(); //注意用long接收
insertSort(tmpArray);
long endTime = System.currentTimeMillis();
System.out.println("直接插入排序耗时:"+(endTime-startTime));
}
}