• 希尔排序


    算法思想

    1. 先取一个正整数d1<n,把所有序号相隔d1的数组元素放一组,组内进行直接插入排序;
    2. 然后取d2<d1,重复上述分组和排序操作;
    3. 直至di=1,即所有记录放进一个组中排序为止。

    如下图,该列表有九个项。如果我们使用三的增量,有三个子列表,每个子列表可以通过插入排序进行排序:

    完成这些排序后,我们得到如下图 所示的列表。虽然这个列表没有完全排序,但发生了很有趣的事情。 通过排序子列表,我们已将项目移动到更接近他们实际所属的位置:

    接下来使用增量为 1 的插入排序; 换句话说,标准插入排序。注意,通过执行之前的子列表排序,我们减少了将列表置于其最终顺序所需的移位操作的总数。对于这种情况,我们只需要四次移位完成该过程:

    动画演示:

    实现

    C++

    void shellSort(vector<int> &array)  
    {
    	int len = array.size();
    
    	int i, j, gap;   // gap为步长,每次减为原来的一半。
    	for (gap = len / 2; gap > 0; gap /= 2)
    	{
    		// 共gap个组,对每一组都执行直接插入排序
    		for (i = 0; i < gap; i++)
    		{
    			for (j = i + gap; j < len; j += gap)
    			{
    				// 如果array[j] < array[j-gap],则寻找array[j]位置,并将后面数据的位置都后移。
    				if (array[j] < array[j - gap])
    				{
    					int tmp = array[j];
    					int k = j - gap;
    					while (k >= 0 && array[k] > tmp)
    					{
    						array[k + gap] = array[k];
    						k -= gap;
    					}
    					array[k + gap] = tmp;
    				}
    			}
    		}
    	}
    }
    

    python

    def shellSort(alist):
        sublistcount = len(alist)//2
    
        while sublistcount > 0:
        #一次将分段的起始元素开始输入到分段插入排序中
          for startposition in range(sublistcount):
            gapInsertionSort(alist,startposition,sublistcount)
    
          sublistcount = sublistcount // 2
    
    #本质上实现的是插入排序
    def gapInsertionSort(alist,start,gap):
        for i in range(start+gap,len(alist),gap):
    
            currentvalue = alist[i]
            position = i
    
            while position>=gap and alist[position-gap]>currentvalue:
                alist[position]=alist[position-gap]
                position = position-gap
    
            alist[position]=currentvalue
    

    总结

    希尔排序的增量:
    希尔排序的增量数列可以任取,需要的唯一条件是最后一个一定为1(因为要保证按1有序)。

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

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

    复杂度:
    (O(N * log N))

  • 相关阅读:
    8086标志
    微内核
    枚举算法
    ajax
    面向对象技术概述
    ajax
    存储技术
    自然数组排列
    将搜索二叉树转换成双向链表
    在单链表中删除指定值的节点
  • 原文地址:https://www.cnblogs.com/chay/p/10675054.html
Copyright © 2020-2023  润新知