Índice
1. Classificação por inserção direta
2. Classificação de inserção binária
3. Use a classificação por inserção no array arr[l...r]
Semelhante a jogar pôquer, ao classificar as cartas, as cartas aleatórias são inseridas na classificação de inserção natural de cartas já codificadas.
1. Classificação por inserção direta
Selecione o primeiro elemento do intervalo não ordenado a cada vez, insira-o na posição apropriada do intervalo ordenado e repita esse processo até que toda a matriz esteja em ordem. O intervalo inteiro é dividido em um intervalo ordenado [0, i) e um intervalo não ordenado [i, n).
/**
* 直接插入排序 稳定的
* 每次选择无序区间的第一个元素,插入到有序区间的合适位置
* @param arr
*/
public static void insertionSortBase(int[] arr) {
//有序区间[0,i) [0,1)
//默认第一个元素就是有序
for (int i = 1; i < arr.length; i++) {
//每次选择无序区间的第一个元素,插入到有序区间的合适位置
//无序区间[i, n)
for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
swap(arr, j, j-1);
//arr[j] > arr[j - 1]此时循环直接终止
//arr[j - 1]已经是有序区间元素,大于前面的所有值
}
}
}
Estabilidade: Estável.
arr[j] > arr[j - 1] o loop é encerrado, portanto, a ordem dos elementos iguais antes e depois da classificação não será alterada.
desempenho:
Complexidade de tempo: n * 1 + (n - 1) * 2 + (n - 2) * 3 + ... + 2 * (n - 1) + 1 * n => O(n ^ 2)
A maior diferença entre classificação por inserção e classificação por seleção é: se arr[j] >= arr[j - 1], o loop pode ser encerrado diretamente e arr[j - 1] já é um elemento de intervalo ordenado.
A classificação por inserção funciona muito bem em tamanhos de dados pequenos, em matrizes quase ordenadas. É frequentemente usado como um método de otimização para algoritmos de classificação avançados.
2. Classificação de inserção binária
Ao selecionar a posição onde os dados devem ser inseridos em um intervalo ordenado, devido à ordem do intervalo, pode-se utilizar a ideia de busca binária (binary search) para localizar rapidamente a posição de inserção.
/**
* 折半插入排序
* @param arr
*/
public static void insertionSortBS(int[] arr) {
for (int i = 1; i < arr.length; i++) {
//无序区间第一个值
int val = arr[i];
//有序区间[0,i)
int low = 0;
int high = i;
while(low < high) {
int mid = (low + high) >> 1;
//将相等的值放在左半区间,保证稳定性
if(val >= arr[mid]) {
low = mid + 1;
}else{
//右区间取不到,不用 -1
high = mid;
}
}
//数据搬移
for (int j = i; j > low; j--) {
arr[j] = arr[j - 1];
}
//low就是元素插入位置
arr[low] = val;
}
}
Estabilidade: Estável.
Complexidade de tempo: n * logn + n * (1...n) => O(N^2)
A classificação por inserção binária (comparar e trocar um por um, O(logn)) é mais rápida do que a classificação por inserção direta (mover elementos após encontrar a posição de inserção, O(n)) principalmente na pesquisa (pesquisa de intervalo ordenado).
O número de movimentos == o número de trocas (porque a posição final de inserção é a mesma).
3. Use a classificação por inserção no array arr[l...r]
/**
* 在数组arr[l...r]上使用插入排序
* @param arr
* @param l
* @param r
*/
private static void insertBase(int[] arr, int l, int r) {
//有序的区间[l...i]
//无序的区间[i...r]
for (int i = l + 1; i <= r; i++) {
for (int j = i; j > l && arr[j] < arr[j - 1]; j--) {
swap(arr, j, j - 1);
}
}
}