【算法】Python & C++实现排序算法(四)之希尔排序

1、希尔排序
参考https://www.jianshu.com/p/d730ae586cf3
参考https://blog.csdn.net/qq_39207948/article/details/80006224
希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。由于直接插入排序,应该说,它的效率在某些时候是很高的,比如, 我们的记录本身就是基本有序的,我们只需要少量的插入操作,就可以完成整个记录集的排序工作,此时直接插入很高效。 还有就是记录数比较少时,直接插入的优势也比较明显。 可问题在于,两个条件本身就过于苛刻,现实中记录少或者基本有序都展 于特殊情况。但是条件不存在,我们创造条件也是可以去做的。 于是科学家希尔研究出了一种排序方法,对直接插入排序改进后可以增加效率。

2、具体思想
那么如何让待排序的记录个数较少呢?很容易想到的就是将原本有大觉记录数的记录进行分组。 分割成若干个子序列,此时每个子序列待排序的记录个数就比较少了,然 后在这些子序列内分别进行直接插入排序,当整个序列都基本有序时,注意只是基本有序时,再对全体记录进行一次直接插入排序。

  1. 那么什么是基本有序呢?
    就是小的基本在前面,大的基本在后面,不大不小的基本在中间2,1,3,6,4,7,5,8,9】满足,而【2,9,3,4,8,2】不是基本有序,为什么会出现这样情况?这就与从哪里开分成子序列的地方有关了,分的点恰当,那经过子序列分别的插入排序整个序列满足剧本有序,反之,则满足不了.
  2. 那么我们因该采取什么原则使得整个序列分为多个子序列?
    采取跳跃分割的策略:将相距某个 “增量“的记录组成一个子 序列,这样才能保证在子序列内分别进行直接插入排序后得到的结果是基本有序而不是局部有序。而对于增量的选择如下,尽管不是最优的选择,但是这个增量序列是比较常用的,也是希尔建议的增量”希尔增量“。第一个增量=length/2,第二个增量= 第一个增量/2,第三个增量=第二个增量/2,以此类推,最后一个增量=1。

现在以序列【8,9,1,7,2,3,5,4,6,0】为例:

第一轮: 增量10/2
【8,3】【9,5】【1,4】【7,6】【2,0】5组,先分别对其直接插入排序后可以得到【3,5,1,6,0,8,9,4,7,2】
在这里插入图片描述
第二轮:增量5/2
被分为2组【3,5,1,6,0】【,8,9,4,7,2】分别进行插入排序得到【0,2,1,4,3,5,7,6,9,8】
在这里插入图片描述
第三轮: 增量2/2
被分为1组【0,2,1,4,3,5,7,6,9,8】直接插入排序,可以得到【0,1,2,3,4,5,6,7,8,9】可以看到排序成功。
在这里插入图片描述
3、时间复杂度
希尔排序的执行时间依赖于增量序列,希尔排序耗时的操作有:比较 + 后移赋值。希尔排序没有快速排序算法快,因此中等大小规模表现良好,对规模非常大的数据排序不是最优选择。【专家们提倡,几乎任何排序工作在开始时都可以用希尔排序,若实际使用中证明它不够快,再改成快速排序这样更高级的排序算法】
时间复杂度情况如下:(n指待排序序列长度)

  1. 最好情况:序列是正序排列,在这种情况下,需要进行的比较操作需(n-1)次。后移赋值操作为0次。即O(n)
  2. 最坏情况:O(nlog2n)。
  3. 渐进时间复杂度(平均时间复杂度):O(nlog2n)

希尔排序在效率上较直接插入排序有较大的改进,同时由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。

4、代码实现

/*
作者:kimicr
时间:20200327
功能:希尔排序
特点:不稳定且时间复杂度【nlogn~ n】
*/
#include"iostream"
using namespace std;

void insert(int *array, int step, int i)	//标准插入排序
{
    
    
	int temp = array[i];
	int j;
	for (j = i - step; j >= 0&&temp<array[j]; j -= step)
	{
    
    
		array[j + step] = array[j];
	}
	array[j + step] = temp;
}


void ShellSort(int *array, int length)
{
    
    
	for (int step = length / 2; step > 0;step /=2)  //增量设置
	for (int i = step; i < length; i++)
		insert(array, step, i);
}

int main()
{
    
    
	int a[] = {
    
     12,15,9,20,6,31,24 };
	ShellSort(a, sizeof(a) / sizeof(a[0]));
	for (int i = 0; i < (sizeof(a)/sizeof(a[0])); i++)
		cout << a[i] << " ";
	cout << endl;
	system("pause");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_32643313/article/details/105158331