一、概念与分类
插入排序的基本思想是:每次将一个待排序的记录,按照其关键字大小插入到前面已经排好序的一组记录当中的适当位置,知道所有待排序记录全部插入为止(类似打扑克的时候插牌)。
一共有两种插入排序算法:直接插入排序(含折半插入排序)和希尔排序。本文总结直接插入排序以及折半插入排序。
二、代码及思路
1.直接插入排序
#include<bits/stdc++.h>
using namespace std;
int insertSort(vector<int> &a) { //数组传参加&,命名为a
int i,j,t;
for(i=1; i<a.size(); i++) {
if(a[i]<a[i-1]) { //当第i个数小于前面那个数时,即需要对第i个数进行插入排序时
t=a[i];
for(j=i-1; j>=0 && a[j]>t; j--) {//遍历前i-1个数,把所有比第i个数大的数往后移
a[j+1]=a[j];
}
a[j+1]=t; //第j+1个位置是给第i个数留的空位,把t填进去
}
}
}
int main() {
vector<int> v;
int n;
cin>>n;
//输入待排序的数组
for(int i=1; i<=n; i++) {
int x;
cin>>x;
v.push_back(x);
}
//调用插入排序函数进行排序
insertSort(v);
//输出排序后的数组内容
for(int i=0; i<v.size(); i++) {
cout<<v[i]<<" ";
}
return 0;
}
代码比较简单,需要注意的是,在遍历前 i-1 个数时,这前 i-1 个数是已经排好序的。
2.折半插入排序
#include<bits/stdc++.h>
using namespace std;
int binInsertSort(vector<int> &a) {
int i,j,t,low,high,mid;
for(i=1; i<a.size(); i++) {
t=a[i];
low=0;
high=i-1;
while(low<=high) {
mid=(low+high)/2;
if(a[mid]>t) high=mid-1;
else low=mid+1;
}
for(j=i-1; j>=high+1; j--) a[j+1]=a[j];
a[high+1]=t;
}
}
int main() {
vector<int> v;
int n;
cin>>n;
for(int i=1; i<=n; i++) {
int x;
cin>>x;
v.push_back(x);//下标从零开始
}
binInsertSort(v);
for(int i=0; i<v.size(); i++) {
cout<<v[i]<<" ";
}
return 0;
}
折半插入排序和直接插入排序差不多,过程的总趟数、排序对象的移动次数、排序所需附加存储空间等都相同;他们的区别在于,折半插入排序在操作时运用到了折半查找,这也意味着它的效率会比直接插入排序高。
上述代码使用了 low 和 high 确定遍历区间为 [low,high] ,当 low 与 high 的相对位置合法时(即low<=high),运用折半查找,比较 t 和 a[mid] 的大小,如果比 t 大,证明要排序的第i个数在遍历区间内部,修改 high 的值为 mid-1 ,缩小遍历区间;反之亦然。然后遍历区间 [i-1,high+1] 的所有数,这里面的数是比 t 大并且有序的,让它们全部后移一位,为t腾出来一个空间,最后把 t 放进去即可。