希尔排序介绍:
希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序(n-增量排序),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法因DL.Shell于1959年提出而得名。 希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止
希尔排序的过程:
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量 dt=1(dt <dt-1 …<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
该方法实质上是一种分组插入方法 比较相隔较远距离(称为增量)的数,使得数移动时能跨过多个元素,则进行一次比[2] 较就可能消除多个元素交换。D.L.shell于1959年在以他名字命名的排序算法中实现了这一思想。算法先将要排序的一组数按某个增量d分成若干组,每组中记录的下标相差d.对每组中全部元素进行排序,然后再用一个较小的增量对它进行,在每组中再进行排序。当增量减到1时,整个要排序的数被分成一组,排序完成。 一般的初次取序列的一半为增量,以后每次减半,直到增量为1。 给定实例的shell排序的排序过程 假设待排序文件有10个记录,其关键字分别是: 49,38,65,97,76,13,27,49,55,04。 增量序列的取值依次为: 5,2,1 ##希尔排序代码如下:
package com.nineweeks.simplesort;
/**
* 希尔排序
*
* 解决插入排序时,复制次数过多的问题,插入排序是时,左边的子数组是有序的
* ,将右边的第一个无序元素放在临时变量中,拿它依次和左边的数组元素进行比较,
* 在合适的地方进行插入,此时平均需要移动n/2次,那个数据需要移动n2/2,这也就是
* 为什么插入排序的时间复杂度为O(n2)
*
* 希尔排序在中大规模的数组排序时,效率并没有快速排序或者并归排序这些时间复杂度
* O(nlgn)快,但是比O(n2)还是要快,而且他的最坏情况和平均情况差别不大
*
* 我们提倡在任务排序工作之前先用shell排序,如果证明他不够快,在用其他高级算法
*
* 希尔排序 也叫作 n-增量排序
* @author NineWeek
* @date 2020/05/07 17:20
**/
public class ShellSort {
private long[] array;
private int nElems;
public ShellSort(int max){
this.array = new long[max];
this.nElems = 0;
}
public void insert(long value){
array[nElems++] = value;
}
/**
* 数组的展示方法
*/
public void display(){
for (int i = 0; i < nElems ; i++) {
System.out.print(array[i]+" ");
}
System.out.println();
}
public void sort(){
int inner,outer;
long temp;
int h=1;
while(h<=nElems/3){ //找到初始的增量值(最大增量值)
h=h*3+1;
}
while(h>0){
//控制外层循环(例如nElems = 160,增量区间依次为) 121 40 13 4 1
for(outer = h;outer<nElems;outer++){
temp = array[outer];
inner = outer;
while (inner>h-1 && array[inner-h]>=temp){
array[inner] = array[inner-h];
inner-=h;
}
array[inner] = temp;
}
h=(h-1)/3;
}
}
public static void main(String[] args){
int max = 10;
ShellSort shellSort = new ShellSort(max);
for(int j=0;j<max;j++){
long n = (int)(Math.random()*99);
shellSort.insert(n);
}
shellSort.display();
shellSort.sort();
shellSort.display();
}
}
输出结果:
