## **希尔排序(插入排序的改良版)**
在希尔排序出现之前,计算机界普遍存在“排序算法不可能突破O(n2)”的观点。希尔排序是第一个突破O(n2)的排序算法,它是简单插入排序的改进版。希尔排序的提出,主要基于以下两点:
1. 插入排序算法在数组基本有序的情况下,可以近似达到O(n)复杂度,效率极高。
2. 但插入排序每次只能将数据移动一位,在数组较大且基本无序的情况下性能会迅速恶化。
## **算法描述**
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,具体算法描述:
* 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
* 按增量序列个数k,对序列进行 k 趟排序;
* 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
## **希尔排序的增量**
希尔排序的增量数列可以任取,需要的唯一条件是最后一个一定为1(因为要保证按1有序)。但是,不同的数列选取会对算法的性能造成极大的影响。上面的代码演示了两种增量。
切记:增量序列中每两个元素最好不要出现1以外的公因子!(很显然,按4有序的数列再去按2排序意义并不大)。
下面是一些常见的增量序列。
\- 第一种增量是最初Donald Shell提出的增量,即折半降低直到1。据研究,使用希尔增量,其时间复杂度还是O(n2)。
第二种增量Hibbard:{1, 3, ..., 2k-1}。该增量序列的时间复杂度大约是O(n1.5)。
第三种增量Sedgewick增量:(1, 5, 19, 41, 109,...),其生成序列或者是9*4i**\- 9*2i + 1或者是4i - 3\*2i + 1。
## **稳定性**
我们都知道插入排序是稳定算法。但是,Shell排序是一个多次插入的过程。在一次插入中我们能确保不移动相同元素的顺序,但在多次的插入中,相同元素完全有可能在不同的插入轮次被移动,最后稳定性被破坏,因此,Shell排序不是一个稳定的算法。
## **适用场景**
Shell排序虽然快,但是毕竟是插入排序,其数量级并没有后起之秀--快速排序O(n㏒n)快。在大量数据面前,Shell排序不是一个好的算法。但是,中小型规模的数据完全可以使用它。
## **JAVA代码实现**
Donald Shell增量
```
public static void shellSort(int[] arr){
int temp;
for (int delta = arr.length/2; delta>=1; delta/=2){ //对每个增量进行一次排序
for (int i=delta; i<arr.length; i++){
for (int j=i; j>=delta && arr[j]<arr[j-delta]; j-=delta){ //注意每个地方增量和差值都是delta
temp = arr[j-delta];
arr[j-delta] = arr[j];
arr[j] = temp;
}
}//loop i
}//loop delta
}
```
O(n3/2) by Knuth
```
public static void shellSort2(int[] arr){
int delta = 1;
while (delta < arr.length/3){//generate delta
delta=delta*3+1; // <O(n^(3/2)) by Knuth,1973>: 1, 4, 13, 40, 121, ...
}
int temp;
for (; delta>=1; delta/=3){
for (int i=delta; i<arr.length; i++){
for (int j=i; j>=delta && arr[j]<arr[j-delta]; j-=delta){
temp = arr[j-delta];
arr[j-delta] = arr[j];
arr[j] = temp;
}
}//loop i
}//loop delta
}
```
- JDK常用知识库
- JDK各个版本安装
- Java8流
- 算法
- 十大排序算法
- 冒泡排序
- 选择排序
- 插入排序
- 归并排序
- 快速排序
- 堆排序
- 希尔排序
- 计数排序
- 桶排序
- 基数排序
- 总结
- 常用工具类
- 浮点型计算
- 时间格式处理
- 常用功能点思路整理
- 登录
- 高并发
- 线程安全的单例模式
- Tomcat优化
- Tomcat之APR模式
- Tomcat启动过慢问题
- 常用的数据库连接池
- Druid连接池
- 缓存
- Redis
- SpringBoot整合Redis
- 依赖和配置
- RedisTemplate工具类
- 工具类使用方法
- Redis知识库
- Redis安装
- Redis配置参数
- Redis常用Lua脚本
- MongoDB
- SpringBoot操作MongoDB
- 依赖和配置
- MongoDB工具类
- 工具类使用方法
- 消息中间件
- ActiveMq
- SpringBoot整合ActiveMq
- 框架
- SpringBoot
- 定时任务
- 启动加载
- 事务
- JSP
- 静态类注入
- SpringSecurity
- Shiro
- 配置及整合
- 登陆验证
- 权限验证
- 分布式应用
- SpringMVC
- ORM框架
- Mybatis
- 增
- 删
- 改
- 查
- 程序员小笑话
- 我给你讲一个TCP的笑话吧
- 二进制笑话
- JavaScript的那点东西
- JavaScript内置对象及常见API详细介绍
- JavaScript实现Ajax 资源请求
- JavaScript干货
- 架构师成长之路
- JDK源码解析
- ArrayList源码解读
- 设计模式
- 微服务架构设计模式
- 逃离单体炼狱
- 服务的拆分策略
- 全面解析SpringMvc框架
- 架构设计的六大原则
- 并发集合
- JUC并发编程
- 搜索引擎
- Solr
- Solr的安装
- 分布式服务框架
- Dubbo
- 从零开始学HTMl
- 第一章-初识HTML
- 第二章-认识HTML标签