【排序算法】—— 希尔排序

目录

一、希尔排序原理

二、希尔排序的思路

三、希尔排序为什么快

四、如何取增量

五、源码


希尔排序是简单插入排序的一种升级版,它也是用了插入的思想,而插入排序相比冒泡排序和选择排序的效率要高的多,再将它优化为希尔排序后效率跟原来根本就不在一个级别。接下来我们就一起来学习一下希尔排序

一、希尔排序原理

希尔排序的原理是插入排序,接下来先讲一下简单插入排序

简单插入排序原理:

首先假设第一个元素就是一个小数组并且是有序的,然后把第二个元素当做新加入的元素,依次++往前遍历把它放在合适的位置保持小数组有序++ ,同理把第三个元素当做新加入的元素,依次往前遍历把它放在合适的位置保持前面的小数组有序,依次重复下去直到把大数组的最后一个元素给放置好,这有点像高等代数里的++基底扩充定理++,从一个小的空间覆盖到整个大的空间。

动态图:

cpp 复制代码
//简单插入排序
void InsertSort(int* a, int sz)
{
	for (int i = 0; i < sz - 1; i++)
	{
		int j = i, tmp = a[i + 1];
		while (j >= 0 && tmp < a[j])
		{
			a[j + 1] = a[j--];
		}
		a[j + 1] = tmp;
	}
}

如果一个数组储存数据是++顺序有序++ 的时候效率是最高的++时间复杂度为O(n)++。

有的时候该排序遇到一些极端的情况还是比较低效的,比如需要将一组数组进行升序排序,如果这组数据恰好是降序(即逆有序)的话就会很麻烦时间复杂度O(N^2),它需要将新元素前面的所有数据都遍历完。为了解决类似的问题就引入了希尔排序。

二、希尔排序的思路

希尔排序的原理还是插入排序,就是在做简单插入排序之前做一下预处排序,

先把数据分组,如上图分为(1),(2),(3)三组,然后分别对这三组进行简单插入排序,这是一次预排序。

那么这三组是如何分出来的呢?主要是涉及到一个增量的问题,如上图的增量是3,在取第(1)组元素时每隔3个元素取一次,第(2)第(3)组同样,直到把每个元素都取到。

排完上面三组后继续减小增量分组进行简单插入排序,比如排完以3为增量的三组后,再把增量变为2分为二组,最后当增量为1的时候相当于对整个大组做了一个简单插入排序,排完这一趟后这个数组就有序了,希尔排序结束。

三、希尔排序为什么快

简单插入排序的时间复杂度为O(N^2),而希尔排序的时间复杂度大概为O(N^1.3),当然这还与如何取增量有关。

希尔排序确实比之前的简单插入排序所排的组数要多,因为简单插入排序相当于只排了一组,那么它为什么还那么快呢?

因为它大大的减少了数据挪动次数,在做预排序的时候它是以增量的跨度去挪动的,这就使一个数据更快的接近它的准确位置(也就是排序后它该在的位置)。

四、如何取增量

希尔排序的核心就在于通过设定不同的增量序列来优化插入排序的性能。增量序列的选择对排序速度有显著影响。一般来说,增量序列的选择涉及多种策略,而最佳的增量序列并没有一个固定的标准。比较常用效果比较好的增量设定为size/3+1。size为数组长度。

五、源码

cpp 复制代码
#include<stdio.h>
//单组排
void ShellSort1(int* a, int sz)//(一组排完再排另一组)
{
	int gap = sz;//增量
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < gap; i++)
		{
			for (int j = i; j < sz - gap; j += gap)
			{
				int m = j;
				int tmp = a[j + gap];
				while (m >= 0 && tmp < a[m])
				{
					a[m + gap] = a[m];
					m -= gap;
				}
				a[m + gap] = tmp;
			}
		}
	}
}
//多组一起排
void ShellSort2(int* a, int sz)
{
	int gap = sz;//增量
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < sz - gap; i++)
		{
			int j = i;
			int tmp = a[i + gap];
			while (j >= 0 && tmp < a[j])
			{
				a[j + gap] = a[j];
				j -= gap;
			}
			a[j + gap] = tmp;
		}
	}
}
int main()
{
	int arr[] = { 8,3,4,9,2,6,5,7,1,10 };
	int size = sizeof(arr) / sizeof(int);
	ShellSort1(arr, size);
	for (int i = 0; i < size; i++)
		printf("%d ", arr[i]);
	return 0;
}
相关推荐
Musennn1 小时前
leetcode 15.三数之和 思路分析
算法·leetcode·职场和发展
CM莫问3 小时前
<论文>(微软)避免推荐域外物品:基于LLM的受限生成式推荐
人工智能·算法·大模型·推荐算法·受限生成
康谋自动驾驶4 小时前
康谋分享 | 自动驾驶仿真进入“标准时代”:aiSim全面对接ASAM OpenX
人工智能·科技·算法·机器学习·自动驾驶·汽车
C++ 老炮儿的技术栈5 小时前
什么是函数重载?为什么 C 不支持函数重载,而 C++能支持函数重载?
c语言·开发语言·c++·qt·算法
yychen_java6 小时前
R-tree详解
java·算法·r-tree
MarkHard1236 小时前
Leetcode (力扣)做题记录 hot100(62,64,287,108)
算法·leetcode·职场和发展
王RuaRua6 小时前
[数据结构]5. 栈-Stack
linux·数据结构·数据库·链表
一只鱼^_7 小时前
牛客练习赛138(首篇万字题解???)
数据结构·c++·算法·贪心算法·动态规划·广度优先·图搜索算法
一只码代码的章鱼7 小时前
Spring的 @Validate注解详细分析
前端·spring boot·算法
邹诗钰-电子信息工程7 小时前
嵌入式自学第二十一天(5.14)
java·开发语言·算法