插入排序
在大概率有序的或者元素较小(20个左右)的情况下使用;
思想:
将无序部分插入到有序的部分
找要插入的位置:(两种方法)
1、顺序查找(在大概率有序情况下)
2、二分查找(无序情况下,较顺序查找较快)
时间复杂度:
平均:O(N^2);
使用顺序查找时,最好的情况为O(N);
最坏:O(N^2)
空间复杂度:O(1)
稳定性:稳定排序(稳定:不会改变相同元素的相对顺序)
代码实现:
顺序查找插入排序(直接插入排序)
//升序
//顺序查找法
public static void insertSort(int[] arr) {
//[0, i)有序区间
for(int i = 1; i < arr.length; ++i) {
//给属于无序位置i在有序区间[0, i)找合适的插入位置
int boundValue = arr[i];
int j = i;
for(; j > 0; --j) {
if(arr[j - 1] > boundValue) {//当前处理值的前一个值若大于当前i的值
arr[j] = arr[j - 1];//就一个一个往前移动
}else {//当前位置合适
break;
}
}
arr[j] = boundValue;//将当前找出合适位置的值赋值为之前未被覆盖之前i的值
}
}
二分查找插入排序
//二分查找法
public static void insertSortBin(int[] arr) {
for(int i = 1; i < arr.length; ++i) {
int boundValue = arr[i];
int index = BinSearch(arr, i - 1, boundValue);//返回找到的位置
//将有序区间[0, i)中(index, i]后移,将index位置空出
for(int j = i; j > index; j--) {
arr[j] = arr[j-1];
}
arr[index] = boundValue;
}
}
private static int BinSearch(int[] arr, int n, int boundValue) {
int left = 0;
int right = n;
int mid = 0;
while(left <= right) {
mid = (left+right)/2;
if(boundValue > arr[mid]) {
left = mid + 1;
}else {
right = mid - 1;
}
}
return left;
}
//二分查找
//mid已经比较,所以right/left需要前移/后移一位
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int mid;
while (left <= right) {
mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;
}
}
希尔排序
该排序算法是基于若排序序列尽可能有序,插入排序会很快的想法
思想:分组插排
1、先做预排序(使排序序列尽可能有序)
组内数据间隔逐渐变小,密度逐渐变小
2、开始插入排序
时间复杂度:
平均情况:O(N^1.3)
最好情况:O(N)
最坏情况:O(N^2)
空间复杂度:O(1)
代码实现:
public static void shellSort(int[] array) {
// 使用希尔序列:n/2, n/4, n/8...1
// 分组的组大小逐渐增大,一个组的数据间隔越来越小
for (int group = array.length / 2; group >= 1; group /= 2) {
for (int i = group; i < array.length; ++i) {
int boundValue = array[i];
int j = i;
for (; j >= group; j -= group) {// 分组插排
if (array[j - group] > boundValue) {
array[j] = array[j - group];
} else {
break;
}
}
array[j] = boundValue;
}
}
}