从直接插入排序到希尔排序

希尔排序需要和直接插入排序我们来联合起来进行比较。

1.直接插入排序

首先我们来看直接插入排序:
这里写图片描述

直接插入排序就是一个将无序区的内容向有序区放的一个过程,有序区不断地变大,无序区不断的变小,这样最后全部变为有序,就完成了直接插入排序的过程了。

算法步骤:

1)将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。

2)从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)

示例代码:

template<typename T>
void InsertSort(T* arr, int size)
{
    int pos = 0;
    for (int index = pos + 1; index < size; index++)
    {
        pos = index - 1;
        T tmp = arr[index];
        while (pos >= 0 && arr[pos] < tmp)
        {
            arr[pos + 1] = arr[pos];
            pos -= 1;
        }
        arr[pos + 1] = tmp;
    }

}

接下来我们首先来讨论下直接插入排序,对于直接插入排序而言最好的情况就是接近于有序的时候,这个时候我们再次进行直接插入排序的时候效率就会很高,而最差的时候莫过于逆序的时候,这个时候需要和有序区的元素比较很多次。所以为了解决这个问题,一个叫做希尔的人提出了希尔排序。

2.希尔排序

关于希尔排序,其实就可以理解为让直接插入排序最差的变得更加高效

希尔排序的思想就是一种类似的分治的思想,首先我们把一个序列分成多个模块,然后对每个模块中对应下标相同的元素进行排序,这样就可以达到最快速度的把大的放前面,小的放后面(如果是升序相反)。

所以希尔排序的实质是把序列变成接近有序的序列,然后进行一次直接插入排序。

这里写图片描述

代码实现:

#define _CRT_SECURE_NO_WARNINGS 1

#include<iostream>
#include<cstdlib>

using namespace std;

//希尔排序是为了解决直接插入排序的最差情况的排序,直接插入排序的最好情况是近似有序,最差情况是逆序,希尔排序就是把最差情况变得接近有序。
//希尔排序将数组划分为几个块,然后对对应的快的下标求余相同的元素进行排序,能够快速达到把大的放前面,小的放后面(如果是升序相反)。


template<typename T>
void ShellSort(T *arr, int size)
{

    int gap = size;
    while (gap > 1)
    {
     //注意这里的增量每次取除3+1。
        gap = gap / 3 + 1;
        int pos = 0;
        //在这里希尔排序实际操作是按照顺序方式操作,并不是预想的一个模块一个模块的。操作的时候是对gap中的每一个进行希尔排序完以后再到下一个gap进行希尔排序。
          for (int index = pos + gap; index < size; index++)
        {
            pos = index - gap;
            T tmp = arr[index];
            while (pos >= 0&&arr[pos] < tmp)
            {
                arr[pos+gap] = arr[pos];
                pos -= gap;
            }
            arr[pos+gap] = tmp;
        }

    }
}

希尔排序需要注意的是gap需要给一个大值。

3.总结

希尔排序是一种更加高效的插入排序,它和直接插入排序的时间复杂度虽然都在O(N)—O(N^2)之间,但是希尔排序来说是更加高效的,它的平均时间复杂度大约是O(N^1.3)。当希尔排序的最好情况对于直接插入排序而言就是最差情况,希尔排序的最差情况对于直接插入排序而言就是最好情况。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值