保姆教学第四弹:希尔排序及其优化

希尔排序,是改进的插入排序。其核心思想是:给定一个间隔gap,按照这个间隔将待排序数组的数,跳着“取出来”,形成一个新待排序数组,然后对这个新数组进行插入排序。间隔缩小,重复上述过程,知道gap==1。
希尔排序演示:

假设间隔gap=4,第一轮
希尔排序演示
然后,gap对半,gap=2,重复上述,直到gap==1,结束排序。
我们开始写算法程序吧。

首先,这个是改进的插入排序,我们先把插入排序写好。在插入排序的基础上,改进。

#include<iostream>

void swap(int a[], int i, int j) {
	int temp = a[i];
	a[i] = a[j];
	a[j] = temp;
}
static void Shellsort(int a[], int length);//函数头
static void Shellsort(int a[], int length) {
		for (int i = 1; i < length; i++) {//why i++
			for (int j = i; j > 0; j --) {
				if (a[j] < a[j - 1]) {
					swap(a, j, j - 1);
				}
			}
		}
	
}
int main() {
	using std::cout;

	int a[] = { 9,6,11,3,5,12,8,7,10,15,14,4,1,13,2 };
	int length = sizeof(a) / sizeof(a[0]);

	Shellsort(a, length);

	for (auto i : a) cout << i << " ";

	//cin.get();//在按下enter键之前,任何键击将不被发送给程序
	return 0;
}

根据希尔排序思想,要点1:设置间隔。
·从简单到复杂,一点点完成。
假设我们把间隔gap定位4,先完成间隔为4的第一次排序。其实就是把插入排序的间隔为1,改为了间隔为4。所以,外面的循环从gap开始,代替了1,里面的内循环,j>0改为j>gap-1,j–改为j=j-gap。

static void Shellsort(int a[], int length) {
      int gap=4;
	for (int i = gap; i < length; i++) {//why i++
	//间隔不再是1了,改为gap=4,所以此时j>gap-1,防止越界
			for (int j = i; j > gap - 1; j -= gap) {
				if (a[j] < a[j - gap]) {
					swap(a, j, j - gap);
				}
			}
		}
}

完成了第一次循环,接下来就很简单了。就是不断把间隔缩小,一直到gap=1。很容易想到,再加一个gap的for循环,控制gap。
所以,最终的希尔排序就是这样。

我们设定为间隔为4的希尔排序如下:

static void Shellsort(int a[], int length) {
	for (int gap = 4; gap > 0; gap /= 2) {
		for (int i = gap; i < length; i++) {//why i++
			for (int j = i; j > gap - 1; j -= gap) {
				if (a[j] < a[j - gap]) {
					swap(a, j, j - gap);
				}
			}
		}
	}
}

是不是,一步一步就写出来啦,万事开头难。

简单的优化

对希尔排序进行优化,其实就是对他的间隔设置进行优化,如何找到“恰到好处”的间隔,能让排序效率更快一点。

间隔设置

♣ 第一种:常见的以待排序数组的一半,不断缩小,对半。gap==N/2(N为数组长度)

static void Shellsort(int a[], int length) {
	//将length/2改为位运算:右移一位length >> 1,给面试官的印象更好
	for (int gap = length >> 1; gap > 0; gap /= 2) {
		for (int i = gap; i < length; i++) {//why i++
			for (int j = i; j > gap - 1; j -= gap) {
				if (a[j] < a[j - gap]) {
					swap(a, j, j - gap);
				}
			}
		}
	}
}

小tips:将int gap = length ;改为位运算,右移一位。应该给面试官的印象更好一点。

♣ 第二种:Knuth序列

gap=1;
gap=3*gap+1
当gap超过整个数组的1/3。就不合适了。
间隔,采用Knuth序列要比采用N/2,效率要高一些。

static void Shellsort(int a[], int length) {

	int h = 1;
	while (h <= length/3)
	{
		h = h * 3 + 1;
	}
	//将length/2改为位运算:右移一位length >> 1,给面试官的印象更好
	for (int gap = h; gap > 0; gap =(gap-1)/3) {
		for (int i = gap; i < length; i++) {//why i++
			for (int j = i; j > gap - 1; j -= gap) {
				if (a[j] < a[j - gap]) {
					swap(a, j, j - gap);
				}
			}
		}
	}
}

End.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值