插入排序
插入排序
网上找的动图
插入排序就像码牌。
-
每次拿到一个新的牌到手里,都从右往左地比较一下,
比如手里有1,2,4,5,抓到一张3,那就先和5比,3小于5,把5往后挪一下,3占到5原来的位置;
3再和4比,发现3比4小,把4往后挪一下,3占4原来的位置;
3再和2比,发现3比2大,那么3就到此停住,站住自己的位置(由此说明插入排序是稳定的)。因为2以前都是有序的。
所以插入排序就是认为,数组里的数分为有序的部分和无序的部分。最开始只有第一个数是有序的,然后从第二个数开始遍历,每一个数都和前面有序的部分做比较交换,并找到属于自己的位置。最后所有的数都进入有序的部分,排序结束。
算法实现
static void sort(int[] arr) {
if (null == arr) {
return;
}
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
// 每个数都和前面的数作比较,如果后面的数比前面的小,则交换
if (arr[j] < arr[j - 1]) {
swap(arr, j, j - 1);
}
}
}
}
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
这种写法很直接,直接比较交换。
换一种写法(从网上摘的)
static int[] insertSort(int[] sourceArr) {
if (null == sourceArr) {
return null;
}
// 对 arr 进行拷贝,不改变参数内容
int[] targetArr = Arrays.copyOf(sourceArr, sourceArr.length);
// 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
for (int i = 1; i < sourceArr.length; i++) {
// 记录要插入的数据
int temp = targetArr[i];
// 从已经排序的序列最右边的开始比较,找到比其小的数
int j = i;
while (j > 0 && temp < targetArr[j - 1]) {
targetArr[j] = targetArr[j - 1];
j--;
}
// 存在比其小的数,把这个数插入到第j个槽上
if (j != i) {
targetArr[j] = temp;
}
}
return targetArr;
}
换一种说法,对数组排序,等价于:对数组的0~倒数第二个数排序,然后把最后一个元素插入到这个有序数组中。其实这个说法就很像递归了。存在子问题,问题规模在变小。
递归的形式
static void recursiveSort(int[] arr) {
recursiveSort(arr, 0);
}
static void recursiveSort(int[] arr, int i) {
if (i >= arr.length) {
return;
}
// 0~i插入排序
int j = i;
int temp = arr[i];
while (j > 0 && temp < arr[j - 1]) {
arr[j] = arr[j - 1];
j--;
}
if (i != j) {
arr[j] = temp;
}
// arr的0~i部分已经排好序了,子问题就是计算i+1位置的数的排序
recursiveSort(arr, i + 1);
}