基本思想:
通常人们整理桥牌的方法是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。在计算机的实现中,为了要给插入的元素腾出空间,我们需要将其余所有元素在插入之前都向右移动一位。
算法描述:
一般来说,插入排序都采用in-place在数组上实现。具体算法描述如下:
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
注意:
如果 “比较” 操作的代价比 “交换” 操作大的话,可以采用二分查找法来减少比较操作的数目。该算法可以认为是插入排序 的一个变种,称为二分查找插入排序。
代码实现:
/**
* 通过交换进行插入排序,借鉴冒泡排序
*
* @param a
*/
public static void sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
for (int j = i + 1; j > 0; j--) {
if (a[j] < a[j - 1]) {
int temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
}
}
}
}
/**
* 通过将较大的元素都向右移动而不总是交换两个元素
*
* @param a
*/
public static void sort2(int[] a) {
for (int i = 1; i < a.length; i++) {
int num = a[i];
int j;
for (j = i; j > 0 && num < a[j - 1]; j--) {
a[j] = a[j - 1];
}
a[j] = num;
}
}
/**
* 二分插入排序
*
* @param source
*/
public static void binarySort(int[] source) {
int i, j;
int high, low, mid;
int temp;
for (i = 1; i < source.length; i++) {
// 查找区上界
low = 0;
// 查找区下界
high = i - 1;
//将当前待插入记录保存在临时变量中
temp = source[i];
while (low <= high) {
// 找出中间值
// mid = (low + high) / 2;
mid = (low + high) >> 1;
//如果待插入记录比中间记录小
if (temp<source[mid] ) {
// 插入点在低半区
high = mid - 1;
} else {
// 插入点在高半区
low = mid + 1;
}
}
//将前面所有大于当前待插入记录的记录后移
for (j = i - 1; j >=low; j--) {
source[j + 1] = source[j];
}
//将待插入记录回填到正确位置.
source[low] = temp;
printArray(source);
}
}
复杂度分析:
直接插入排序复杂度如下:
平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 |
---|---|---|---|
O(n²) | O(n²) | O(n²) | O(1) |