/**
* 插入排序
* 依次从未排序的部分拿出第一个元素,插入到已排序的元素中合适的位置
* 时间o(n²)
*/
public class InsertionSort {
public static int[] sort(int[] nums) {
// 选择1个未排序的元素
for (int i = 1; i < nums.length; i++) {
// 拿未排序的元素和已排序的元素进行比较(从右向左),如果比已排序的最后一个元素小则继续和已排序元素比较,否则当前元素位置就是合适排序位置
for (int j = i; j > 0; j--) {
if (nums[j] < nums[j-1]) {
nums[j] = nums[j-1] + nums[j];
nums[j-1] = nums[j] - nums[j-1];
nums[j] = nums[j] - nums[j-1];
} else {
break;
}
}
System.out.println(Arrays.toString(nums));
}
return nums;
}
public static void main(String[] args) {
sort(new int[]{8, 6, 2, 3, 1, 5, 7, 4});
}
}
上述插入排序算法有个可以优化的地方,就是在内层循环中比较的时候会一直交换数组中元素的值。
改进办法为将当前未排序数字拿一个变量保存起来,然后进行从右向左比较,这种只需确定元素位置后交换一次值即可,具体实现如下:
public static void sortOptimize(int[] nums) {
// 选择一个未排序的元素
for (int i = 1; i < nums.length; i++) {
// 用变量j记录未排序元素应该存在的位置,temp记录未排序元素的值
int j, temp = nums[i];
for (j = i; j > 0; j--) {
if (temp < nums[j - 1]) {
// 向右挪动元素
nums[j] = nums[j - 1];
} else {
break;
}
}
nums[j] = temp;
System.out.println(Arrays.toString(nums));
}
}
改进后的插入排序算法比改进前能减少一半的时间消耗,此处以100000个数字进行排序:
public static void main(String[] args) {
int[] nums = SortHelper.generate(100000, 100000);
int[] copyNums = Arrays.copyOf(nums, nums.length);
long startTime = System.currentTimeMillis();
sort(nums);
System.out.println(String.format("耗时:%s", (System.currentTimeMillis() - startTime))); // 1951
startTime = System.currentTimeMillis();
sortOptimize(copyNums);
System.out.println(String.format("耗时:%s", (System.currentTimeMillis() - startTime))); // 965
}
插入排序比选择排序快一点,是因为插入排序满足条件之后可以退出第二次遍历,选择排序每次都得找到未排序元素中的最值。