插入排序与希尔排序

1)插入排序

插入排序是一种非常古老的排序思想,他的过程可以被形象的模拟出来:假设一个人要摸起一副被打乱的扑克牌,我们注意到,刚开始时这个人手上并没有牌,并且他每次只从牌堆中摸出一张牌,每当摸上一张牌时,他选择从右向左(即从大到小)将这张牌与手中原有的牌进行比较,并最终将其插入到自己手牌中适合的位置,当牌堆中的牌全部被摸出时,他便完成了一次简单的插入排序。
这里面显然有一些规律:
第一,这个人手中的牌始终是有序的,因为他始终将摸上来的牌按顺序插入手牌中;
第二,在整个插入排序的过程中,我们每次只拿出一个元素来对他进行比较操作,因此,插入排序的空间效率是O(1)。
第三,每次将牌插入手牌时,牌与手牌的比较次数,实际上取决于原本牌堆中不同大小的牌的摆放顺序。因此,该算法的效率并不稳定,当牌堆中牌按照从小到大分布,这意味着每一次我们摸起一张牌,都可以直接将他插入手牌的最右边,这样我们拥有了O(n)级别的时间效率。而当牌堆中牌按照从大到小分布,意味着每一次的插入,我们都需要将该牌与手牌中所有的牌比较一遍,并将它置于手牌的最左边,这显然需要浪费大量的时间,时间效率实际上降低到了O( n 2 n^2 n2)。
因此,我们需要对简单的插入排序进行改进。

(插入排序C++代码实现)

template<class t>
void insert_sort(t Array[], int n) {
//Array中存放待排序数组,n为数组长度
	t current_insert;
	for (int i = 0; i < n; i++) {
		current_insert = Array[i];
		int j = i - 1;
		while ((j >= 0) && (current_insert < Array[j])) {
			Array[j + 1] = Array[j];
			j--;
		}
		Array[j + 1] = current_insert;
	}
}

2)希尔(Shell)排序

希尔排序实际上是对插入排序的优化处理。
算法思想 :

  1. 现将待排序序列转换成若干个小序列,对于这些小序列内部进行插入处理。
  2. 在确定当前小序列都排序完毕后,逐渐增加小序列的规模,并减少小序列的个数,使得该待排序列整体逐渐处于更有序的状态
  3. 这时我们发现,该待排序序列逐渐接近扑克牌问题中的最优情况,这时候对排队进行一次整体的插入排序,能达到接近O(n)的算法效率。

以上就是希尔排序的全部算法思想,这里面最重要的部分很显然就在于“逐渐增加小序列的规模,并减少小序列的个数”。我们需要找到一个合适的方法来控制小序列的规模,从而能尽可能的增加排序的效率。
我们用gap来表示增量,首先选择一个增量gap=n/2,当我们完成了该规模下小序列的排序时,再按照gap=gap/2的规则来改变增量,这时我们实际上得到了一个关于增量的序列{n/2,n/2/2…,1}。注意这里最后一步的增量一定为1,这意味着按照当前增量序列进行希尔排序,我们不需要再额外进行一次整体的插入排序。
在这里插入图片描述
如上图所示,遵循希尔排序的第一个增量n/2,我们从乱序数组的第一个元素开始,将每个元素跳跃着与他后面第n/2个元素进行插入排序,我们实际上将原数组分为了{4,7},{2,8},{9,4},{3,11},{1,10}这五组数据,并对每一组数据分别进行插入排序。
在这里插入图片描述
第二步,遵循希尔排序的第二个增量n/2/2,我们将待排序数组分为{4,4,1,8,11},{2,3,7,9,10}两组,并分别对两组数据进行插入排序。
在这里插入图片描述
最后一步我们对整个数据整体进行希尔排序,可以看到进行到最后一步时,该数组已经非常接近于一个正序数组,这将始我们最后一次插入排序的效率非常接近于O(n)

针对gap=gap/2的增量序列的代码实现

template<class t>
void shell_sort(t Array[], int n) {
	int i, dealta;
	for (delta = n / 2; delta > 0; delta /= 2) {
		for (int i = 0; i < delta; i++)
			insert_sort(&Array[i], n - i; delta);
	}
}

当然,这种增量序列仍然存在很多可以改进的地方,由于我们只是单纯的对于增量进行了不断除2的操作,这导致我们选取的增量并不互质,这导致在我们比较的过程中,可能会产生某些位置之间被重复多次比较的可能性,降低了算法的处理效率,Hibbard等各种增量序列是一个可行的解决方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值