百度百科:有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
插入排序的基本思想是:每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。在网上找了一个动画,如下图所示:
下面上代码:(这是一个简单插入排序)
// 简单插入排序
public static void insertSort(int[] a) {
int j, temp;
for (int i = 1; i < a.length; i++) {
temp = a[i];
if (a[i] < a[i - 1]) {
// 这里可以进行一次判断 只有当a[i]<a[i-1]时才进入循环进行交换
// 因为前面已经有序了,只需要比较最大值,最大值不满足无需交换
for (j = i - 1; j >= 0 && a[j] > temp; j--) {
a[j + 1] = a[j];
}
a[j + 1] = temp;
}
}
}
由于待排序列是有序的,所以我们可以联想到折半查找,为了找到a[i]的插入位置,我们使用折半查找的方法可以加快效率:
public static void binaryInsertSort(int[] a) {
int j, temp, k;
for (int i = 1; i < a.length; i++) {
temp = a[i];
if (a[i - 1] >= temp) {
j = binarySearch(a, 0, i - 1, temp);
for (k = i; k > j; k--)
a[k] = a[k - 1];
a[j] = temp;
}
}
}
// 折半插入排序
public static int binarySearch(int[] a, int low, int high, int temp) {
int mid;
if (temp < a[low])
return low;
while (low <= high) {
mid = (low + high) / 2;
if (a[mid] <= temp && temp < a[mid + 1]) {
return mid + 1;
} else if (a[mid] > temp) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
这里特别需要注意的一个问题是我们在根据一个关键值在排好序的数组中查找位置时,数组有可能不存在这个数,所以可以返回-1;但是我们在查找插入位置时,总是可以找到一个可以插入的位置.所以当temp比前面所有已经排好序的数都小时,我们找到的插入位置应该是low,这种特殊的情况一定要考虑到.
插入排序的进化版就是希尔排序.原理是:把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。通常情况下宏观上调整的排序算法要比微观调整的排序算法效率高.下面上代码:
public static void shell(int[] a, int d) {
int temp, j;
for (int i = d; i < a.length; i += d) {
temp = a[i];
if (a[i - d] > temp) {
for (j = i - d; j >= 0 && a[j] > temp; j -= d) {
a[j + d] = a[j];
}
a[j + d] = temp;
}
}
}
public static void shellSort(int[] a) {
for (int d = 5; d >= 1; d -= 2) {
shell(a, d);
}
}