算法原理
每次从无序部分选择一个元素,将其插入到有序部分的正确位置,重复这个过程直至整个数组有序。
算法描述
插入排序是一种简单直观的排序算法,它的基本思想是将一个待排序的元素插入到已经排序好的序列中的适当位置,从而得到一个新的、长度加一的有序序列。插入排序的过程类似于整理扑克牌的过程。
具体步骤如下:
- 从第二个元素开始,将其视为待排序的元素。
- 将待排序的元素与已排序的序列从右向左进行比较,直到找到合适的位置。
- 将待排序的元素插入到合适的位置,使得插入后的序列仍然有序。
- 重复步骤2-3,直到所有元素都被插入到有序序列中。
动画演示
代码实现
public static void insertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
算法复杂度
时间复杂度(最坏) | 时间复杂度(最好) | 时间复杂度(平均) | 空间复杂度 | 稳定性 |
O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
插入排序的优化方式:
- 二分查找优化: 在已排序的部分使用二分查找来找到插入位置,而不是逐个比较。这可以减少比较的次数。
public static void binaryInsertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; ++i) {
int key = arr[i];
//使用二分查找确定 key 的插入位置 j。这个位置是已排序部分中第一个大于 key 的元素的位置。
int j = binarySearch(arr, 0, i - 1, key);
// 移动已排序部分中大于key的元素
// 比如原数组第一轮:3 1 5 8 2 7 -> 3 3 5 8 2 7,因为 3 > 1,所以把3 复制过去
System.arraycopy(arr, j, arr, j + 1, i - j);
// 在合适的位置插入key
arr[j] = key;
}
}
private static int binarySearch(int[] arr, int low, int high, int key) {
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == key) {
return mid;
}
if (arr[mid] < key) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
呜呜呜 二分真是思路很简单,细节是魔鬼。
相关概念
• 稳定
:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
• 不稳定
:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
• 时间复杂度
:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
• 空间复杂度
:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。