可以理解爲:將一個序列拆分爲兩個,前面那個序列是有序的,後面那個序列是無序的,每次比較都在無序序列中拿出一個元素,插入到有序序列中合適的位置,直到無序序列都被插入完爲止
- 就好比我們打撲克一樣,每次抓來一張牌,我們都要將它插入到合適的位置,來使手裏的牌有序
例如:
目前有一個序列(5, 2, 0, 1, 3, 1, 4)
- 首先,我們將這個序列當做兩個來看
- 前面是有序的:(5),(因爲一個元素一定是有序的,所以初始時這樣劃分)
- 後面是無序的:(2, 0, 1, 3, 1, 4)
- 我們每次都在後面的序列中拿出首元素和前面那個序列中的元素比較(前面的元素反向遍歷),並插入到前面序列中合適的位置
第一趟排序:
- 2比5小,所以插入到5前面
- (2, 5)(0, 1, 3, 1, 4)
第二趟排序:
- 0比5小,還比2小,所以插入到 2 前面
- (0, 2, 5)(1, 3, 1, 4)
第三趟排序:
- 1比2小,但比0大,所以插入到0和2中間
- (0, 1, 2, 5)(3, 1, 4)
第四趟排序:
- 3比5小,但比2大,所以插入到2和5中間
- (0, 1, 2, 3, 5)(1, 4)
第五趟排序:
- 1比2小,但和1相等,所以插入到1和2中間
- (0, 1, 1, 2, 3, 5)(4)
第六躺排序:
- 4比5小,但比3大,所以插入到3和5中間
- (0, 1, 1, 2, 3, 4, 5)
排序結束,此時已經是一個有序的序列了
Java代碼
package algorithm;
public class Sort {
// 直接插入排序
public static void insertSort(int[] array) {
for (int i = 1 ; i < array.length ; i++) {
int temp = array[i];
int j = i;
// 找到比 array[i] 還小的元素的下標,然後將 array[i] 插入到它後面
while (j > 0) {
// 如果此元素 > temp,就將這個元素後移一位
// array[j-1] 即爲有序序列中的最後一個元素,
// 也就是要比較的第一個元素(因爲是倒序遍歷)
if (temp < array[j - 1]) {
array[j] = array[j - 1];
j--;
} else {
break;
}
}
// 將 array[i] 插入到此位置
if (i != j) {
array[j] = temp;
}
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 2, 0, 1, 3, 1, 4};
Sort.insertSort(array);
// 打印數組
for (int i = 0 ; i < array.length ; i++) {
System.out.print(array[i] + " ");
}
}
}
Java代碼(另一種寫法)
其實兩種思想是一樣的
- 上面那種是先通過不斷與前一個比較,找到要插入的位置,最後將元素插入進去
- 下面這種是將要插入的元素,不斷與前一個比較,然後一點點交換到要插入的位置
下面這種比上面那種方法少了插入那一步,因爲在比較的過程中就已經交換過去了
package algorithm;
public class Sort {
// 直接插入排序
public static void insertSort(int[] array) {
for (int i = 1 ; i < array.length ; i++) {
for (int j = i ; j > 0 ; j--) {
if (array[j] < array[j - 1]) {
int temp = array[j];
array[j] = array[j - 1];
array[j - 1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] array = new int[]{5, 2, 0, 1, 3, 1, 4};
Sort.insertSort(array);
// 打印數組
for (int i = 0 ; i < array.length ; i++) {
System.out.print(array[i] + " ");
}
}
}
時間複雜度
最好情況:O(n),數組有序,每次我們僅需判斷前面的一個元素即可
平均情況:O(n²)
最壞情況:O(n²),數組倒序,每次我們都需要遍歷整個前面的有序序列纔可