二路插入排序

插入排序时需要移动大量元素。为此可用一个辅助的循环数组来减少元素的移动次数。具体做法如下,对于一个待排序的数组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.csdn.net/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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值