核心思想
将数组中的所有元素依次跟前面已经排好的元素相比较,如果选择的元素比已排序的元素小,则交换,直到全部元素都比较过。
排序流程
因此,直接插入排序可以用两个循环完成:
第一层循环:遍历待比较的所有数组元素;
第二层循环:将本轮选择的元素依次与该元素前面已经排好序的元素相比较,如果选择的元素大于前一位元素则交换;
举例说明
排序数组 [16,12ᴬ,14,7,12ᴮ,8] (注:12ᴬ与12ᴮ是为了标记两个的位置)
- 第一次:
12ᴬ < 16 =》交换位置 =》到达左边界,终止交换 =》交换结束后数组变为 [12ᴬ,16,14,7,12ᴮ,8] - 第二次:
14 < 16 =》交换位置 =》14 > 12ᴬ,终止交换 =》交换结束后数组变为 [12ᴬ,14,16,7,12ᴮ,8] - 第三次:
7 < 16 =》交换位置 =》7 > 14 =》交换位置 =》7 < 12ᴬ =》交换位置 =》到达左边界,终止交换 =》交换结束后数组变为 [7,12ᴬ,14,16,12ᴮ,8] - 第四次:
12ᴮ < 16 =》交换位置 =》12ᴮ > 14 =》交换位置 =》12ᴮ !< 12ᴬ,终止交换 =》交换结束后数组变为 [7,12ᴬ,12ᴮ,14,16,8] - 第五次:
8 < 16 =》交换位置 =》8>14 =》交换位置 =》8 < 12ᴮ =》交换位置 =》8 < 12ᴬ =》交换位置 =》8!<7,终止交换 =》交换结束后数组变为 [7,8,12ᴬ,12ᴮ,14,16] - 结束排序
代码实现
public static int[] insertSort(int[] list) {
int temp;//临时变量标记待排元素
int j;//交换时临时变量标记下标
for (int i = 1; i < list.length; i++) {//外层循环从第二个元素开始依次排序
temp = list[i];//标记待排元素
for (j = i - 1; j >= 0; j--) {//内层循环交换
if (temp > list[j]) break;//如果待排元素大于前面的元素,停止交换
list[j + 1] = list[j];//待排元素小于前一位元素,交换
}
list[j + 1] = temp;//将待排元素放置已经排好序的数组最后
}
return list;
}
总结
1、时间复杂度:最好的情况是数组本身就是有序数组,只需判断 n-1 次是否比前一元素小,没有移动元素,时间复杂度为O(n);
最坏的情况是数组本身是逆序,每一次都需要进行循环交换元素,时间复杂度为O(n²)。
2、在示例中可以发现排序前后12ᴬ,12ᴮ的位置顺序没有改变,所以直接插入排序是一个稳定的排序方式。
3、在记录本身有序,或者记录数比较少时,直接插入的优势比较明显