细致解读希尔排序算法与相关的Java代码实现_java

希尔排序(Shell's sort)是一种非常“神奇”的排序算法。说它“神奇”,是因为没有任何人能清楚地说明它的性能到底能到什么情况。希尔排序因DL.Shell于1959年提出而得名。自从C. A. R. Hoare在1962年提出快速排序后,由于其更为简单,一般采用快速排序。但是,不少数学家们还是孜孜不倦地寻找希尔排序的最佳复杂度。作为普通程序员,我们可以学习下希尔的思路。
顺便说一句,在希尔排序出现之前,计算机界普遍存在“排序算法不可能突破O(n2)”的观点。希尔排序的出现打破了这个魔咒,很快,快速排序等算法相继问世。从这个意义上说,希尔排序带领我们走向了一个新的时代。

算法概述/思路
希尔排序的提出,主要基于以下两点:
1.插入排序算法在数组基本有序的情况下,可以近似达到O(n)复杂度,效率极高。
2.但插入排序每次只能将数据移动一位,在数组较大且基本无序的情况下性能会迅速恶化。

基于此,我们可以使用一种分组的插入排序方法,具体做法是:(以一个16元素大小的数组为例)
1.选择一个增量delta,该增量大于1,从数组中按此增量选择出子数组进行一次直接插入排序。例如,若选择增量为5,则对下标为0,5,10,15的元素进行排序。
2.保留该增量delta并依次移动首个元素进行直接插入排序,直到一轮完成。对于上面的例子,则依次对数组[1,6,11],[2,7,12],[3,8,13],[4,9,14]进行排序。
3.减小增量,不断重复上述过程,直到增量减小为1.显然,最后一次为直接插入排序。
4.排序完成。
从上面可以看出,增量是不断减小的,因此,希尔排序又被成为“缩小增量排序”。

代码实现

package sort; 

public class ShellSortTest {
  public static int count = 0; 

  public static void main(String[] args) { 

    int[] data = new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
    print(data);
    shellSort(data);
    print(data); 

  } 

  public static void shellSort(int[] data) {
    // 计算出最大的h值
    int h = 1;
    while (h <= data.length / 3) {
      h = h * 3 + 1;
    }
    while (h > 0) {
      for (int i = h; i < data.length; i += h) {
        if (data[i] < data[i - h]) {
          int tmp = data[i];
          int j = i - h;
          while (j >= 0 && data[j] > tmp) {
            data[j + h] = data[j];
            j -= h;
          }
          data[j + h] = tmp;
          print(data);
        }
      }
      // 计算出下一个h值
      h = (h - 1) / 3;
    }
  } 

  public static void print(int[] data) {
    for (int i = 0; i < data.length; i++) {
      System.out.print(data[i] + "\t");
    }
    System.out.println();
  } 

} 

运行结果:

5  3  6  2  1  9  4  8  7
1  3  6  2  5  9  4  8  7
1  2  3  6  5  9  4  8  7
1  2  3  5  6  9  4  8  7
1  2  3  4  5  6  9  8  7
1  2  3  4  5  6  8  9  7
1  2  3  4  5  6  7  8  9
1  2  3  4  5  6  7  8  9

算法性能/复杂度
希尔排序的增量数列可以任取,需要的唯一条件是最后一个一定为1(因为要保证按1有序)。但是,不同的数列选取会对算法的性能造成极大的影响。上面的代码演示了两种增量。
切记:增量序列中每两个元素最好不要出现1以外的公因子!(很显然,按4有序的数列再去按2排序意义并不大)。
下面是一些常见的增量序列。
第一种增量是最初Donald Shell提出的增量,即折半降低直到1。据研究,使用希尔增量,其时间复杂度还是O(n2)。
第二种增量Hibbard:{1, 3, ..., 2^k-1}。该增量序列的时间复杂度大约是O(n^1.5)。
第三种增量Sedgewick增量:(1, 5, 19, 41, 109,...),其生成序列或者是9*4^i - 9*2^i + 1或者是4^i - 3*2^i + 1。

算法稳定性
我们都知道插入排序是稳定算法。但是,Shell排序是一个多次插入的过程。在一次插入中我们能确保不移动相同元素的顺序,但在多次的插入中,相同元素完全有可能在不同的插入轮次被移动,最后稳定性被破坏,因此,Shell排序不是一个稳定的算法。

算法适用场景
Shell排序虽然快,但是毕竟是插入排序,其数量级并没有后起之秀--快速排序O(n㏒n)快。在大量数据面前,Shell排序不是一个好的算法。但是,中小型规模的数据完全可以使用它。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, 希尔排序
排序算法
希尔排序算法、希尔排序算法动画演示、希尔排序算法c语言、希尔排序算法过程、希尔排序算法代码,以便于您获取更多的相关知识。

时间: 2024-10-27 09:51:51

细致解读希尔排序算法与相关的Java代码实现_java的相关文章

java实现希尔排序算法_java

希尔排序算法的基本思想是:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组内进行直接插人排序:然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<-<d2<d1),即所有记录放在同一组中进行直接插入排序为止.该方法实质上是一种分组插入方法. //带增量的插入排序 public static void shellSort(int[] array) { int len =

使用Java实现希尔排序算法的简单示例_java

简介希尔排序(缩小增量法) 属于插入类排序,由Shell提出,希尔排序对直接插入排序进行了简单的改进:它通过加大插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项大跨度地移动,当这些数据项排过一趟序之后,希尔排序算法减小数据项的间隔再进行排序,依次进行下去,进行这些排序时的数据项之间的间隔被称为增量,习惯上用字母h来表示这个增量. 常用的h序列由Knuth提出,该序列从1开始,通过如下公式产生: h = 3 * h +1 反过来程序需要反向计算h序列,应该使用 h=(h-

希尔排序算法的C语言实现示例_C 语言

希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本.希尔排序是非稳定排序算法. 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位 希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能.这样可以让一个元素可以一次性地朝最终位置前进一大步.然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几

python实现的希尔排序算法实例

  本文实例讲述了python实现希尔排序算法的方法.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def shellSort(items): inc = len(items) / 2 while inc: for i in xrange(len(items)): j = i temp = items[i] while j >= inc and items[j-inc] > temp: items[j] = items[j - inc]

java中实现希尔排序算法

package Utils.Sort; /**   *希尔排序,要求待排序的数组必须实现Comparable接口   */   public class ShellSort implements SortStrategy   {   private int[] increment; /**   *利用希尔排序算法对数组obj进行排序   */   public void sort(Comparable[] obj)   {   if (obj == null)   {   throw new N

排序算法的相关问题。

问题描述 排序算法的相关问题. while 循环条件里的 i > 0 有什么意义吗 解决方案 保证数组下标合法... 解决方案二: 快速排序算法相关排序算法的相关介绍 解决方案三: 快速排序算法相关排序算法的相关介绍 解决方案四: 循环的结束条件,i-- 当i<=0时结束循环 解决方案五: 循环的结束条件,i-- 当i<=0时结束循环 解决方案六: i>0: 比如这个数组2345,要插入的数是1,那么如果不加i>0会导致程序会无意义的再进入循环一次,我觉的这么做,除了坐标合法

关于希尔排序算法的程序问题

问题描述 关于希尔排序算法的程序问题 源程序为 void shellsort3(int a[], int n) { int i, j, gap; for (gap = n / 2; gap > 0; gap /= 2) for (i = gap; i < n; i++) for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap) Swap(a[j], a[j + gap]); } 如果修改为: void shel

C语言 选择排序算法详解及实现代码_C 语言

选择排序是排序算法的一种,这里以从小到大排序为例进行讲解. 基本思想及举例说明 选择排序(从小到大)的基本思想是,首先,选出最小的数,放在第一个位置:然后,选出第二小的数,放在第二个位置:以此类推,直到所有的数从小到大排序. 在实现上,我们通常是先确定第i小的数所在的位置,然后,将其与第i个数进行交换. 下面,以对 3  2  4  1 进行选择排序说明排序过程,使用min_index 记录当前最小的数所在的位置. 第1轮 排序过程 (寻找第1小的数所在的位置) 3  2  4  1(最初, m

算法难题设计出java代码或者伪代码,大牛请进。

问题描述 算法难题设计出java代码或者伪代码,大牛请进. 把 1 2 3 4 5 6 7 8 9 放入三个数组里面 数组可以是空的.. 数组里面的数 是有序的 比如 {1 2 3} { 4 5 6 } { 7 8 9 }:{356789},{124},{}能穷举吗.打印出来 解决方案 {123456789},{},{} 可以么,如果是可以的话,那么是非常简单的 解决方案二: 我是一个刚刚学习编程半年的小白,有点思路,可能不准确,抛砖引玉.我觉得这个题的实质,是对1 2 3 4 5 6 7 8