插入排序 —— 希尔排序

 希尔排序

 希尔排序也是插入排序的一种。又名缩小增量排序。它是对直接插入排序的一种改进。

直接插入排序是每次都和前面一个元素进行比较。其步长为 1。 希尔排序则不然,它得步长是动态变化的,或者说是由大到小变化的。希尔排序根据步长将整个序列分成n组。然后在各个子组内部分别进行元素的排序。接着缩小步长,相应的序列被分成的子组也就会减少,每个分组内部的元素个数也就相应的增加。接着对子组内部的元素进行排序。再次缩小步长,再次排序。。。。直到步长为 1,即整个序列只有一个子组,也就是序列本身。这个时候再次进行排序即为最终排序。

假设有这样一串序列

a=[23,19,31,47,52,16,45,21]  

如图所示:(从小到大排序)

第一次设置步长为4,相同颜色即为一个分组。然后每个相同颜色的方框内的元素相互比较,调整大小,因为是从小到大排序,所以,小的在前,大的在后。从而得到排序结果。

然后调整步长,再次分组

如图所示:

 第二次步长调整为了原来的一半,分成了两组。重复刚才的对相同颜色的方框内的元素进行排序的动作,小的在前,大的在后,得到排序结果

再次调整步长,再次分组

如图所示:

第三次步长调整,步长为 1,分组为1 ,这是最大分组了。还是重复组内排序的的动作。得到最终结果。

希尔排序就是这样,分组——排序——分组——排序——分组——排序 最终得到最终结果。

代码如下:

def shellSort( A):
    n = len(A)
    gap=n//2     # 设置初始步长, 同时也代表着分组的个数。
    while gap>0:   # 步长也就是分组个数最小是 1,只要不为 1 就重复下面的分组--排序动作
        for i in range(gap,n): # 为什么从gap开始呢?一会说
            temp=A[i]  #取出每一个分组内第一个无序区元素
            j=i-gap    #获取该分组内,最大的有序区元素索引
            while j>=0 and temp<A[j]:   # 将无序区第一个元素逐个和该分组内有序区的元素比较。
                A[j+gap]=A[j]     # 因为每个组之间的元素之间是相隔着gap(当前步长)个其他组的元素的,所以,当赋值的时候,也要注意。
                j-=gap      #如果一直满足while循环条件,那么就按当前的步长向前移动
            A[j+gap]=temp   #退出while循环意味着,已经找到了适当的插入的位置。将当前元素插入到合适位置
        gap = gap //2  # 该步长下,所有的分组都进行了排序,那么调整步长,减少分组个数,扩大分组长度。再次进行排序
    return A

a=[23,19,31,47,52,16,45,21]
print(shellSort(a))

为什么循环时, i 要从 gap开始呢?

希尔排序是直接插入排序的改进版本。直接插入排序步长为1,直接插入排序分组也只有一个大的分组,就是它本身。而希尔排序因为步长不是1,所以其分组也是多个。虽然是多个分组,但是每个分组内部排序的时候,还是和直接插入排序是一样的——从该分组内的第二个元素开始,逐个和前面的元素进行比较,直到找到合适的位置。只是这个时候,前一个元素索引不再是 i-1 了,而是 i -gap了。还是因为步长的存在导致的。

在本例中 gap= 4

为什么从4开始呢。是因为前三个元素,i-gap 都小于0,他们各自的分组内没有前一个元素,他们本身就是各自分组的第一个元素。所以就直接从4开始。当然也可以强制从0开始,只是没什么实际意义,做无用功而已。

时间: 2024-10-14 17:33:12

插入排序 —— 希尔排序的相关文章

插入排序) 希尔排序 (最小增量排序)

/** * (插入排序) 希尔排序 (最小增量排序) * @author Cinn * */public class shellSort { /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        int[] array= {48,58,50,98,69,51,27,99,100};        shlees

PHP 插入排序 -- 希尔排序

1.希尔排序 -- Shell Insertion Sort 时间复杂度:数学家正在勤劳的探索! 适用条件: 直接插入排序的改进,主要针对移动次数的减少,这取决于"增量队列"的取值.适用的情况凭个人感觉用吧,我也不知道,反正,我并不认为自己是一个程序员,喜欢凭感觉行事. 1 <?php 2 $arr = [3,4,5,1,11,9,27,27,18,20]; 3 4 5 function shellSort(array &$arr,$dt) 6 { 7 // 跟增量相关,

插入排序—希尔排序(Shell`s Sort)原理以及Java实现

希尔排序是1959 年由D.L.Shell 提出来的,相对直接排序有较大的改进.希尔排序又叫缩小增量排序 基本思想: 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全体记录进行依次直接插入排序. 操作方法: 选择一个增量序列t1,t2,-,tk,其中ti>tj,tk=1: 按增量序列个数k,对序列进行k 趟排序: 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序.仅增量因子为

排序 之 冒泡排序 简单选择排序 直接插入排序 希尔排序

排序的基本概念 假设含有n个记录的序列为{r1,r2,--,rn},其相应的关键字分别为{k1,k2,--,kn},需确定1,2,--,n的一种排序p1,p2,--,pn,使其相应的关键字满足kp1≤kp2≤--≤kpn非递减(或非递增)关系,即使得序列称为一个按关键字有序的序列{rp1,rp2,--,rpn},这样的操作就称为排序. 排序的稳定性 假设ki=kj(1≤i≤n,1≤j≤n,i≠j),且在排序前的序列中ri领先于rj(即i<j).如果排序后ri仍领先于rj,则称所用的排序方法是稳定

直接插入排序&amp;希尔排序

1.直接插入排序 时间复杂度O(n2) 工作原理: 通过构建有序序列,对于未排序数据,在已排序的序列中,从后向前扫描,找到相应的位置并插入. 插入排序在实现上,在从后向前扫描的过程中,需要反复把已排序元素逐步向后移动,为最新元素提供插入空间. //直接插入排序 public static void InsertSort(int[] a,int n){ int i,j,t; for(i=1;i<n;i++){ t=a[i];//取出一个未排序的数据 for(j=i-1;j>=0&&

内部排序-&gt;插入排序-&gt;希尔排序

文字描述 希尔排序又称缩小增量排序,也属于插入排序类,但在时间效率上较之前的插入排序有较大的改进. 从之前的直接插入排序的分析得知,时间复杂度为n*n, 有如下两个特点: (1)如果待排序记录本身就是"正序"时, 其时间复杂度可减少为n. (2)当待排序记录数很小时,直接插入排序的效率也比较高; 希尔排序正是从这两点分析出发对直接插入排序进行了改进.它的基本思想是:先将整个待排记录序列分割成为若干个子序列分别进行直接插入排序,待整个序列中的记录"基本有序"时,再对全

直接插入排序/二分插入排序/希尔排序

---恢复内容开始--- 插入排序是在源数据已经有序的情况下进行排序.时间复杂度O(N^2),稳定的 直接插入排序 代码如下 public static int[] insertSort(int [] a){ if(a==null||a.length==0){ return a;} for(int i=1;i<a.length;i++){ for(int j=i-1;j>=0&&a[j]>a[j+1];j--) swap(a,j,j+1);//满足前一个大于后一个才进行交

4.2_8种常用排序算法2(插入排序:直接插入排序+希尔排序)

[插入排序] [直接插入排序实例] package com.sort.demo2; import java.util.Arrays; /** * 插入排序 */ public class InsertSort { public static void main(String[] args) { int[] arr = new int[]{1,4,5,7,3,9,8,0,2,6}; System.out.println(Arrays.toString(arr)); insertSort(arr);

插入排序/希尔排序/快速排序C语言实现

#include<stdio.h> #include<stdlib.h> #include<string.h> void swap(int *a,int *b) { int tmp=*a; *a=*b; *b=tmp; } void insertSort(int *a,int n) { int tmp,i,j; for(i=1;i<n;i++) { tmp=a[i]; for(j=i;j>0&&tmp<a[j-1];j--)//find