面试管都在问 | 希尔排序

比较类排序系列-希尔排序

1. 原理

希尔排序是对插入排序的扩展。插入排序是对所有数据进行排序,而希尔排序会把数据分成多个分组,每组数据内部进行插入排序,这样的分组插入排序会进行多次,直到最后所有数组都归为一组,整体再进行一次插入排序,则排序完成。假设间隔为gap, 则希尔排序会把数据中任意间隔为gap的数据划分为一组数据,这样就会有gap个分组,每个分组进行插入排序。gap不断的从大到小变化,直到gap为1时,就退化为基本的插入排序。

算法过程如下图所示
在这里插入图片描述

  • 从上图可以看到,每一遍中,相同颜色的数据被分成了一组,组内进行的为插入排序。上图演示了gap初始值从5开始,第一遍排序中,被分成了5组数据,每组数据只包含2个数据,这5组数据分别进行插入排序。第二遍排序中,gap为2, 被分成了2组数据,同样的2组数据分别进行插入排序。第三遍排序中,gap为1, 此时就退化成基本的插入排序,所有数据为一组,进行插入排序,最终整个数据有序。需要注意的是,最后一遍排序,gap必须为1,这样才能保证整个数据有序。
  • 在这里希尔排序相当于做了多次的插入排序,而当gap不为1时,经过插入排序之后,整体还没有达到有序,但是数据在慢慢的接近有序。所以希尔排序是对数据先做预排序,待数据接近有序之后,再进行插入排序就比较快了。
  • 希尔排序快的原因在于,它让数据移动的距离更远,不像插入排序,数据只是在相邻的位置之间移动,从整体上减少了数据移动的次数,进而提高了排序的性能。
1.1gap的变化

一般gap的变化是有规律的,gap的初始值一般是数据长度的二分之一或者三分之一,之后每次减少二分之一或者三分之一,直到gap为1,执行完最后一次插入排序之后,完成排序。

2. 代码

void shellSort(int* array, int n)
{
	int gap = n;
	while (gap > 1)
	{
        //对数据进行分组
        //每组数据进行插入排序: 间隔为gap的为同一组数据
		gap = gap / 3 + 1;
		// gap > 1:  预排序
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
            //间隔为gap的为同一组数据
			int key = array[end + gap];
			while (end >= 0 && array[end] > key)
			{
				array[end + gap] = array[end];
				end -= gap;
			}
			array[end + gap] = key;
		}
	}
}
public static void shellSort(int[] arr){
        //对数据进行分组
        //每组数据进行插入排序: 间隔为gap的为同一组数据
        int gap = arr.length;
        while(gap > 1){
            gap = gap / 3 + 1;
          
            for(int i = 0; i < arr.length - gap; ++i){
                int end = i;
                //间隔为gap的为同一组数据
                int key = arr[end + gap];

                while(end >= 0 &&arr[end] > key){
                    arr[end + gap] = arr[end];
                    end -= gap;
                }
                arr[end + gap] = key;
            }
        }
    }

3. 时间空间复杂度

3.1 时间复杂度

希尔排序的时间复杂度分析比较困难,这里只给出结论。

  • 最好时间复杂度:O(n^1.3)
  • 最坏时间复杂度:O(n^2)
3.2 空间复杂度

希尔排序中占用的空间为常数个空间,所以其空间复杂度为O(1)。

总结

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值