开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第20天,点击查看活动详情
1、写在前面
大家好,今天文章的内容是:
- 插入排序
2、内容
算法思想
算法思想:
在每一轮循环中,将一个待排序的值按其关键字大小插入到前面已排好序的子序列中,直到全部记录插入完成。
示意举例:
下面举一个例子:
现在有一个未排序的序列:
这时我们将序列中的第一个值视为已排序完毕:
接着从第二个元素开始,我们会认为当前元素之前的部分是已经排完序的序列,接着我们需要将当前元素与已经排序完毕的序列进行逐一比较。对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
以下是排序过程中的示意图:
代码实现:
// C++
void InsertSort(int arr[], int n) {
int i, j, temp;
// 将各个元素插入到已经排好序的序列中
for(i = 1; i<n; i++) {
// 当前 arr[i] 小于前驱元素
if(arr[i] < arr[i-1]) {
// 用 temp 暂存 arr[i]
temp = arr[i];
// 检查所有前面已经排好序的元素,将所有大于temp的元素都往后移一位
for(j = i-1; j >= 0 && arr[j] > temp; --j) {
arr[j+1] = arr[j];
}
// 将temp复制到插入位置中
arr[j+1] = temp;
}
}
}
效率分析:
- 空间复杂度:
- 时间复杂度:
-
- 最好时间复杂度:,共
n-1趟处理,每一趟只需要对比关键字1次,不用移动元素
- 最好时间复杂度:,共
-
- 最坏时间复杂度:,共
n-1趟处理,每一趟都需要从尾移到到头(全部逆序)
- 最坏时间复杂度:,共
- 算法稳定性:稳定
算法优化
思路:先用折半查找法,找到应该插入的位置,再移动元素
- 当
low > high时,折半查找停止,将[low, i-1]内的元素全部右移,并将arr[0]复制到low所指位置 - 当
arr[mid] == arr[0]时,为了保证算法的 “稳定性”,应继续在mid所指位置右边寻找插入位置。
代码实现
void InsertSort(int arr[], int n) {
int i,j,low,high,mid;
// 依次将 arr[2]~arr[n] 插入到前面已排完序的序列
for(i=2; i<=n; i++) {
// 将arr[i] 暂存到 arr[0] (哨兵)
arr[0] = arr[i];
// 设置折半查找的范围
low = 1; high = i-1;
// 折半查找(默认递增有序)
while(low <= high) {
// 取中间点
mid = (low+high) / 2;
// 查找左半子表
if(arr[mid] > arr[0]) high = mid - 1;
// 查找右半子表
else low = mid + 1;
}
// 统一后移元素,空出插入位置
for( j = i-1; j >= high+1; --j) {
arr[j+1] = arr[j];
}
// 将之前暂存的元素插入到指定位置arr[high+1]中(这里的 high+1 就相当于 low )
arr[high+1] = arr[0];
}
}
3、写在最后
好了,文章的内容就到这里,感谢观看。