插入排序时需要移动大量元素。为此可用一个辅助的循环数组来减少元素的移动次数。具体做法如下,对于一个待排序的数组a,我们首先找到一个与a相同大小的循环数组。然后按照以下操作进行。
1.令b[0]=a[0]。因为一个元素总是有序的。
2.令两个指针first和final指向b中已存在元素的最大和最小值。
3.对于从a[1]开始的元素,我们从b中寻找其正确的插入位置。这时会出现三种情况。如果a[i]小于b[first]时,我们把first指针向前移动一位,然后令first所指元素的值为a[i]。反之如果a[i]>b[final],我们把final指针向后移动一位。如果不是以上两种情况,我们就在first和final构成的“环形”中,寻找a[i]的正确插入位置。
可以看到,这会出现两种极端情况。第一种是,每次扫描都会遇到一个最大值或者最小值,这种情况下不需要进行任何的移动元素操作,每一步都直接修改指针即可。另一种情况是每次扫描都遇不到最大值和最小值,这时就需要在first和final构成的“环形”中进行常规的插入操作,二路插入排序退化成普通的插入排序。
代码如下:
参考了http://blog.youkuaiyun.com/caroline_wendy/article/details/24267679的代码,做了一些修改。
// 2-wayInsertSort.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <deque>
using namespace std;
void print(const std::deque<int>& L) {
for (auto i : L) {
std::cout << i << " ";
}
std::cout << std::endl;
}
void insertSort(std::deque<int>& L)
{
int first(0), final(0);
std::size_t n(L.size());
std::deque<int> D(n);
D[0] = L[0];
for (std::size_t i = 1; i<n; ++i) {
if (L[i] < D[first]) { //小于最小元素
first = (first - 1 + n) % n; //头部增长一个单位
D[first] = L[i];
print(D);
}
else if (L[i] > D[final]) { //大于最大元素
++final; //尾部不会超过最大长度-1
D[final] = L[i];
print(D);
}
else {
//折半查找
int low(0), high((final - first) % n);
int temp(first), end(high);
while (low <= high) {
int m = (low + high) / 2;
if (L[i] < D[(m + temp) % n])
high = m - 1;
else
low = m + 1;
}
for (int j = end; j >= high + 1; --j) {
D[(j + temp + 1) % n] = D[(j + temp) % n];
}
D[(high + temp + 1) % n] = L[i];
final = (final + 1 + n) % n;
print(D);
}
}
//复制数组
for (std::size_t k = 0; k<n; k++) {
L[k] = D[(first + k) % n];
}
}
int main(void)
{
std::deque<int> L = { 9, 3, 2, 4, 5, 8, 7, 6 };
print(L);
insertSort(L);
print(L);
system("pause");
return 0;
}