插入排序
上个一定能懂的代码先:
// 进行简单的元素位置交换
public static void swap(int arr[], int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 插入排序操作
public static void insertShort(int arr[]) {
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);
}
}
}
}
// 或者直接这么写:
public static void insertShort(int arr[]) {
for(int i = 1; i < arr.length; i++) {
for(int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
swap(arr, j, j-1);
}
}
}
对上面的代码进行简单的优化一下:
public static void insertShort(int arr[]) {
for(int i = 1; i < arr.length; i++) {
// 零时变量来记录
int t = a[i];
int j = i;
for(; j > 0 && t < arr[j - 1]; j--) {
a[j] = a[j - 1];
}
arr[j] = t;
}
}
折半插入排序
加入二分查找进行插入排序:
public static void binInsertSort(int arr[]) {
// 第i个数
for (int i = 1; i < arr.length; i++) {
int target = arr[i];
// 找到插入的位置
int index = binSearch(arr, i);
index = index >= 0 ? index : -index - 1;
// 移出一个空位来
move(arr, index, i - index);
// 将元素插入到该有的位置
arr[index] = target;
}
}
/**
*传入查找元素的下标索引(此元素已经存储在此数组中),查找目标元素的前面所有元素是否存在和目标元素相等的值,存在则返回第一次出现的索引位置,若不存在则返回插入位置(取反之后再减去1)
*@param arr 待排序的数组
*@param targetIndex 查找元素的索引
*/
private static int binSearch(int arr[], int targetIndex) {
int start = 0;
int end = targetIndex - 1;
while(start <= end) {
int mid = (start + end) >>> 1;
if(arr[targetIndex] > arr[mid]) {
start = mid + 1;
} else if(arr[targetIndex] < arr[mid]) {
end = mid - 1;
} else {
return mid;
}
}
return -start - 1;
}
private static void move(int[] arr, int start, int num) {
if(arr == null || start < 0 || start >= arr.length || num < 1 || num > arr.length) {
return;
}
for (int i = start + num; i > start; i--) {
arr[i] = arr[i - 1];
}
}
或者是:
public static void binInsertSort(int[] arr) {
for (int i = 1; i < arr.length; i++) {
int low = 0, high = i - 1;
int temp = arr[i];
while (low <= high) {
int mid = (high + low) >>> 1;
if (arr[mid] > temp) {
high = mid - 1;
} else {
// 元素相同时,也插入在后面的位置
low = mid + 1;
}
}
for (int j = i - 1; j >= low; j--) {
arr[j + 1] = arr[j];
}
arr[low] = temp;
}
}
当然你也可以用其他的实现方式,重要的是掌握这个算法的思想。
折半插排稳定性及复杂度
序算法是一种稳定的排序算法,比直接插入算法明显减少了关键字之间比较的次数,因此速度比直接插入排序算法快,但记录移动的次数没有变,所以折半插入排序算法的时间复杂度仍然为,与直接插入排序算法相同。附加空间O(1)。
折半插入排序的记录比较次数与初始序列无关。因为每趟排序折半寻找插入位置时,折半次数是一定的,折半一次就要比较一次,所以比较次数也是一定的。
折半查找只是减少了比较次数,但是元素的移动次数不变,所以时间复杂度为是正确的!