这样写感觉会出现问题,但是目前看来是可以进行插入排序的(如果题目要求给出每一趟插入排序的结果而且元素个数不多的时候应该可以用这个)
如果会出什么问题请看到的朋友及时指出!
void insert_sort(vector<int> &A)
{
for(auto it = A.begin() + 1;it != A.end();it++){
if(*it < *(it-1)){
int x = *it;
auto pos = lower_bound(A.begin(), it-1, x);
A.erase(it);
A.insert(pos, x);
// 下面可以输出本次插入排序的结果
}
}
}
带个注释的较详细版本
void insert_sort(vector<int> &A)
{
for(vector<int>::iterator it = A.begin() + 1;it != A.end();it++)
{
if(*it < *(it-1))
{
// 记录待插入的值,不然erase后it不指向待插入的值,会出问题
int x = *it;
// pos就是要插入的位置(这应该算折半插入排序吧)
vector<int>::iterator pos = lower_bound(A.begin(), it-1, x);
// erase和insert必须是erase在前,我认为是insert在前的话会再次分配空间,导致it失效
// 而erase在前元素少了并不会再次分配空间,所以daijobu
A.erase(it);
A.insert(pos, x); // pos是在it之前的位置,所以insert后it会变回指向原来的位置(似乎啥都没发生的样子)
}
}
}
再来个正常版本的折半插入排序吧
# include <iostream>
# include <array>
# include <vector>
# include <algorithm>
using namespace std;
const int N = 8;
template<typename T>
int BiSearch(const T & A, int low, int high, int x)
{
// 一般的寻找插入位置时low < high
// 但这里是low <= high而不是low < high,是为了保证插入位置的稳定性,
// 使算法在结束时再进行一次low = mid + 1;以保证稳定性
while(low <= high)
{
int mid = (low+high) / 2;
if(x < A[mid])
high = mid - 1;
else
low = mid + 1;
}
return high;
}
template <typename T>
void show(const T & A)
{
for(int i : A){
cout << i << " ";
}cout << endl;
}
void insert_sort(array<int, N> &A)
{
for(int i=1;i<A.size();++i)
{
if(A[i] < A[i-1])
{
int x = A[i];
// 如果按照模板写的话,就需要pos-1(因为pos是要插入位置的前一位,在模板里,pos找到的就是要插入的位置)
// 可以用lower_bound或upper_bound代替,但是算法的稳定性似乎就不能保证了,关于稳定性我现在不想研究分析,目前不太关心……
int pos = BiSearch(A, 0, i-1, x);
// 循环结束条件是pos+1还是pos都没影响,只是条件为pos时,pos+1也就是待插入元素将要被放到的地方被pos处的元素先覆盖了而已;
//而条件为pos时pos+1处的元素没有被覆盖,还是原来的元素。当循环结束后,无论是那种情况,pos+1都会被待插入元素给覆盖。
for(int j=i-1;j>=pos+1;--j)
A[j+1] = A[j];
A[pos+1] = x;
}
}
}
int main()
{
array<int, N> A = {3, 7, 2, 8, 1, 5, 4, 7};
// vector<int> A = {3, 7, 2, 8, 1, 5, 4, 7}; // 用vector测试就用这个
show(A);
insert_sort(A);
show(A);
}