简介
插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。
插入排序算法的运作如下:
-
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
-
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
视觉图效果
代码实现
public int[] insertSort(int[] nums){
int swapCount = 0;
int i, j;
for (i = 1; i < nums.length; i++) {
int temp = nums[i];
for (j = i; j > 0 && temp < nums[j - 1]; j--) {
swapCount ++;
nums[j] = nums[j - 1];
}
nums[j] = temp;
}
System.out.println(" " + swapCount);
return nums;
}
测试
测试用例
- 数组长度1
- 数组长度10
- 数组长度100
- 数组长度1000
- 数组长度10000
- 数组长度100000
- 数组长度1000000
期望:数组长度越大,耗时越长,且呈现几何倍数递增
测试条件
硬件环境
配置项 | 配置值 |
---|---|
computer | MacBook Pro (Retina, 13-inch, Early 2015) |
graphics | Intel Iris Graphics 6100 1536 MB |
member | 16 GB 1867 MHz DDR3 |
processor | 3.1 GHz Dual-Core Intel Core i7 |
测试代码
public class AppTest {
App app = new App();
int[] one = new int[1];
int[] two = new int[10];
int[] three = new int[100];
int[] four = new int[1000];
int[] five = new int[10000];
int[] six = new int[100000];
@Before
public void before(){
one = generateRandomNumber(1);
two = generateRandomNumber(10);
three = generateRandomNumber(100);
four = generateRandomNumber(1000);
five = generateRandomNumber(10000);
six = generateRandomNumber(100000);
}
@Test
public void testDoItOne(){
System.out.print(1 + " ");
app.insertSort(one);
System.out.println("----------------");
}
@Test
public void testDoItTwo(){
System.out.print(2 + " ");
app.insertSort(two);
System.out.println("----------------");
}
@Test
public void testDoItThree(){
System.out.print(3 + " ");
app.insertSort(three);
System.out.println("----------------");
}
@Test
public void testDoItFour(){
System.out.print(4 + " ");
app.insertSort(four);
System.out.println("----------------");
}
@Test
public void testDoItFive(){
System.out.print(5 + " ");
app.insertSort(five);
System.out.println("----------------");
}
@Test
public void testDoItSix(){
System.out.print(6 + " ");
app.insertSort(six);
System.out.println("----------------");
}
// @Test
public void testDoItSeven(){
System.out.print(7 + " ");
int[] seven = generateRandomNumber(1000000);
long start = System.currentTimeMillis();
app.insertSort(seven);
long end = System.currentTimeMillis();
System.out.println("----------------");
System.out.println("耗时:"+ (end - start));
}
public static int[] generateRandomNumber(int length){
int[] randomArray = new int[length];
Random random = new Random();
for(int i=0;i<length;i++){
randomArray[i] = random.nextInt(length);
}
return randomArray;
}
}
测试结果
总结
T(1) = 长度1的数组排序耗时
毫秒级:T(1), T(10), T(100), T(1000) 10毫秒
秒级:T(10000) 50毫秒
十秒级:T(100000) 4.45秒
百秒级:T(1000000) 344秒
从上到下递增倍数是:5倍, 9倍, 100倍
分水岭是数组长度10000.
整个排序期间,并未创建多余的数组占用内存(除了几个用户辅助判断查找次数,交换次数的变量)
在插入排序中,当待排序数组是有序时,是最优的情况,只需当前数跟前一个数比较一下就可以了,这时一共需要比较N- 1次,时间复杂度为 O(n);
最坏的情况是待排序数组是逆序的,此时需要比较次数最多,总次数记为:1+2+3+…+N-1,所以,插入排序最坏情况下的时间复杂度为O(n*n)。
时间复杂度:O(n) ~ 0(n*n)
空间复杂度:O(1)
从时间复杂度上看,插入排序 = 选择排序性能 < 鸡尾酒冒泡排序 < 冒泡排序