排序算法——希尔排序

希尔排序


我对希尔排序进行学习的博客:希尔排序–简单易懂图解

前言

可以说是一个加强版的插入排序。在插入排序中,最好的时间复杂度是 O ( N ) O(N) O(N)可以说是极其舒服的线性时间复杂度,而这最好的情况,就是当数组中所有的数都是有序的时候,这是 O ( N ) O(N) O(N)的复杂度。或者稍微比较好的情况,就是数组中大部分数都是有序的时候,那么,插入排序的时间复杂度,将趋近于 O ( N ) O(N) O(N),也就是线性的复杂度。而希尔排序的思想本质就是让数组中的数在尽可能少的次数内,变得有序起来,从而缩短整体时间复杂度,当然这思想没有脱离插入排序的基本做法,所以希尔排序的最坏时间复杂度,依然是 O ( N 2 ) O(N^2) O(N2),但在平均的情况下,希尔排序的时间复杂度将会是挺可观的。

基本做法

对数组进行分组(逻辑上的分组),然后对每个分组进行插入排序,使分组中的数变得有序,因为被分组后,每个分组中的数都不是很多,所以单次分组后的插入排序相对来说不会有过高的时间复杂度。然后经过多次分组然后执行插入排序后,数组中的数在整体上的有序程度会逐步拔高,直到最后一次对整体的插入排序,时间复杂度基本趋近于线性 O ( N ) O(N) O(N)。而这个分组的依据就很关键了,在希尔排序中使用的则是与计算机紧密相关的数2

例:长度为8的数组
每次对数组(整除2所得到的间隔值(gap))进行分组,然后对每个分组进行插入排序,因为最后间距(gap)必定是1,所以,前面的可以说是利用数字2的特性,进行的数组有序程度的提高,然后最后进行一个时间复杂度相对低的整体插入排序。最终达到整体时间复杂度的降低。

第一次分组: 8 / / 2 = 4 8 // 2 = 4 8//2=4
在这里插入图片描述
第二次分组: 4 / / 2 = 2 4 // 2 = 2 4//2=2
在这里插入图片描述

第三次分组: 2 / / 2 = 1 2 // 2 = 1 2//2=1
在这里插入图片描述

代码构造思路

注:下面所说的分组有序数组都是逻辑上的。

首先最外层的循环,自然是要套上每次的分组依据,也就是gap值的循环for (int gap = len >> 1; gap > 0; gap >>= 1)。数组中的每个数相隔gap个位置为一组。其次的第二层循环则是要循环上当前需要排序的整个数组for (int i = gap; i < len; ++i),而第二层循环从gap开始,则是因为,数组中gap值前面位置的数在各自分组中都是第一个数,而gap值的位置开始到最后的数,一开始都还没有插入到各自的有序分组之中,所以每个分组,当前只有一个数,而分组中只有一个数,自然这个分组当前是有序的。最后的insertI(nums, gap, i),其实就跟插入排序差不了多少,把当前数插入到有序数组中正确的位置即可。

代码

class Solution {
public:
	Solution() {}
	~Solution() {}

	void insertI(vector<int>& nums, int gap, int i) {
		int insertNum = nums[i];
		int j;
		for (j = i - gap; j >= 0 && insertNum < nums[j]; j -= gap) {
			nums[j + gap] = nums[j];
		}
		nums[j + gap] = insertNum;
	}

	vector<int> sortArray(vector<int>& nums) {
		int len = nums.size();
		for (int gap = len >> 1; gap > 0; gap >>= 1) {
			for (int i = gap; i < len; ++i) {
				insertI(nums, gap, i);
			}
		}
		return nums;
	}
};

时间复杂度

平均情况最好情况最坏情况
O ( N 1.3 ) O(N^{1.3}) O(N1.3) O ( N ) O(N) O(N) O ( N 2 ) O(N^2) O(N2)

注:这平均情况的时间复杂度不太好算。

空间复杂度

辅助存储
O ( 1 ) O(1) O(1)

PS:这个算法很明显是不稳定的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值