插入排序(Insertion Sorting)的基本思想
把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
说通俗一点,如果你玩过斗地主(扑克),那么你理牌的过程就是插入排序。发给你的牌是一个无序表(设为A),你手中的牌是一个有序表(设为B)。你从A中拿起一张牌,会在B中找一个合适的位置,这个位置后面的点数大于这张牌,这个位置前面的点数小于这张牌,找到位置后就将这张牌插入B,最终B中的牌都是有序的。
代码实现
public class InsertSort {
public static void main(String[] args) {
int[] nums = new int[]{10, 2, 11, 56, 0, 8, 90, 22, 1, 66};
for (int num : nums) {
System.out.print(num + "\t");
}
System.out.println();
insertSort(nums);
for (int num : nums) {
System.out.print(num + "\t");
}
System.out.println();
}
// 升序排序
public static void insertSort(int[] nums) {
// 外层循环从第二个数开始遍历,nums[i]表示待插入的数
for (int i = 1; i < nums.length; i++) {
int j = i;
// 用临时变量保存这个待插入的数
int temp = nums[i];
// 如果待插入的数小于它的前一个数就要进行移位,否则不操作
if (temp < nums[j - 1]) {
// 一直进行移位操作,直到temp找到合适的位置,这个位置的索引就是while循环结束后的j
while (j - 1 >= 0 && temp < nums[j - 1]) {
nums[j] = nums[j - 1];
j -= 1;
}
// 插入
nums[j] = temp;
}
}
}
}
结果
10 2 11 56 0 8 90 22 1 66
0 1 2 8 10 11 22 56 66 90
时间复杂度为O(n^2)
测试耗时
// 创建随机数
public static int[] createNum(int size, long seed) {
int[] nums = new int[size];
Random random = new Random(seed);
for (int i = 0; i < nums.length; i++) {
nums[i] = random.nextInt(1000);
}
return nums;
}
// 测试5轮
public static void testTime(int size) {
// 使用不同的种子,使每一轮测试的随机数不一样
// 种子也可以用于其他排序,因为Random是个伪随机数类,
// 只要种子相同,两个Random对象产生的随机数也一样,
// 利用这个特点在测试其他排序时,使用种子一样,他们排序的数据
// 也一样
int[] seeds = new int[]{9999, 8888, 7777, 6666, 5555};
int[] nums = createNum(size, seeds[0]);
long start = System.currentTimeMillis();
insertSort(nums);
long end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
nums = createNum(size, seeds[1]);
start = System.currentTimeMillis();
insertSort(nums);
end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
nums = createNum(size, seeds[2]);
start = System.currentTimeMillis();
insertSort(nums);
end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
nums = createNum(size, seeds[3]);
start = System.currentTimeMillis();
insertSort(nums);
end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
nums = createNum(size, seeds[4]);
start = System.currentTimeMillis();
insertSort(nums);
end = System.currentTimeMillis();
System.out.println("耗时:" + (end - start) + "ms");
}
结果如下:
耗时:13452ms
耗时:10161ms
耗时:9972ms
耗时:10000ms
耗时:9800ms
#####注意:当被插入的数较小时,数组元素后移的次数会明显增多,对效率有影响。
如:2 3 4 5 6 7 8 1
当1被插入时,前面所有的元素都会向后移动一位,如果数据量较大,这种情况出现的频率也较大,那么就会对效率造成较大影响。
解决办法:请看下一篇:希尔排序