排序算法——希尔排序图文详解(二)

简介: 排序算法——希尔排序图文详解
for (int i = 0; i < numsSize - gap; i++)
{
    int end = i;
    int temp = nums[end + gap];
    while (end >= 0)
    {
        if (temp < nums[end])
        {
            nums[end + gap] = nums[end];
            end -= gap;
        }
        else
            break;
    }
    nums[end + gap] = temp;
}
  • 最后还要不断缩小gap的值,直到gap == 1
int gap = numsSize;
while (gap > 1)
{
    gap /= 2; //不断缩小gap
    /*
      也可以写成 gap = gap / 3 + 1;
      总之,必须要保证最后一次gap == 1
    */
    for (int i = 0; i < numsSize - gap; i++)
    {
        int end = i;
        int temp = nums[end + gap];
        while (end >= 0)
        {
            if (temp < nums[end])
            {
                nums[end + gap] = nums[end];
                end -= gap;
            }
            else
                break;
        }
        nums[end + gap] = temp;
    }
}

实现代码

void ShellSort(int* nums, int numsSize)
{
  int gap = numsSize;
  while (gap > 1)
  {
    gap /= 2;
    for (int i = 0; i < numsSize - gap; i++)
    {
      int end = i;
      int temp = nums[end + gap];
      while (end >= 0)
      {
        if (temp < nums[end])
        {
          nums[end + gap] = nums[end];
          end -= gap;
        }
        else
          break;
      }
      nums[end + gap] = temp;
    }
  }
}

直接插入排序与希尔排序的效率比较

  • 看到希尔排序有三层循环,可能有小伙伴会疑惑希尔排序为什么会比直接插入排序快,这里我们先上测试代码,直观的来感受这两个排序算法之间的差距:

测试代码:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//直接插入排序
void InsertSort(int* nums, int numsSize)
{
  for (int i = 0; i < numsSize - 1; i++)
  {
    int end = i;
    int temp = nums[end + 1];
    while (end >= 0)
    {
      if (temp < nums[end])
      {
        nums[end + 1] = nums[end];
        end--;
      }
      else
        break;
    }
    nums[end + 1] = temp;
  }
}
//希尔排序
void ShellSort(int* nums, int numsSize)
{
  int gap = numsSize;
  while (gap > 1)
  {
    gap /= 2;
    for (int i = 0; i < numsSize - gap; i++)
    {
      int end = i;
      int temp = nums[end + gap];
      while (end >= 0)
      {
        if (temp < nums[end])
        {
          nums[end + gap] = nums[end];
          end -= gap;
        }
        else
          break;
      }
      nums[end + gap] = temp;
    }
  }
}
int main()
{
  srand((unsigned int)time(NULL));
   //创建两个大小为N的数组
  const int N = 100000;
  int* a1 = (int*)malloc(sizeof(int) * N);
  int* a2 = (int*)malloc(sizeof(int) * N);
   //为数组赋随机值
  for (int i = 0; i < N; i++)
  {
    a1[i] = rand();
    a2[i] = a1[i];
  }
   /*
    clock()函数可以记录当前时间
    begin和end的差即排序算法运行的时间
    注:时间的单位为毫秒(ms)
   */
  int beginl = clock();
  InsertSort(a1, N);
  int end1 = clock();
  int begin2 = clock();
  ShellSort(a2, N);
  int end2 = clock();
  printf("InsertSort:%d\n", end1 - beginl);
  printf("ShellSort:%d\n", end2 - begin2);
   //释放内存
  free(a1);
  free(a2);
  return 0;
}

测试结果:

  • 我们可以看到,当数据个数为十万个时,直接插入排序所需要的时间是的希尔排序的100多倍
  • 当数据个数为一百万个时,直接插入排序所需要的时间时希尔排序的2000倍、
  • 可见,数据越多,希尔排序的优势就越明显,节省点时间就越多

时间复杂度

  • 从上面的测试中,我们直观的感受到了相较于直接插入排序,希尔排序的优越性,那么具体的希尔排序的时间复杂度为多少呢?
  • 我们先来看最外层的循环:
int gap = numsSize;
while (gap > 1)
{
    gap /= 2;
    …………
}
  • 设最外层循环运行了x次,那么2x = numsSize,x = log2N,即最外层的时间复杂度为log2N
  • 再看里面两层循环:
for (int i = 0; i < numsSize - gap; i++)
{
    int end = i;
    int temp = nums[end + gap];
    while (end >= 0)
    {
        if (temp < nums[end])
        {
            nums[end + gap] = nums[end];
            end -= gap;
        }
        else
            break;
    }
    nums[end + gap] = temp;
}
  • 当gap很大时,尽管有两层循环,但数据之间跳跃的很大,需要排序的次数很少,因此时间复杂度为O(N),例如这种情况:

  • 当gap很小时,尽管有两层循环,但此时数据已经接近有序,需要排序的次数也很少,因此时间复杂度也为O(N)。
  • 综上,希尔排序的时间复杂度为O(NLog2N)
  • 也可以认为时间复杂度为O(N1.3)
相关文章
|
8月前
|
算法 搜索推荐 Java
数据结构与算法(Java篇)笔记--希尔排序
数据结构与算法(Java篇)笔记--希尔排序
|
7月前
|
算法 搜索推荐
数据结构算法--6 希尔排序和计数排序
**希尔排序**是插入排序的改进版,通过分组插入来提高效率。它逐步减少元素间的间隔(增量序列),每次对每个间隔内的元素进行插入排序,最终增量为1时进行最后一次直接插入排序,实现整体接近有序到完全有序的过程。例如,对数组`5, 7, 4, 6, 3, 1, 2, 9, 8`,先以间隔`d=4`排序,然后`d=2`,最后`d=1`,完成排序。计数排序则适用于0到100的数值,通过统计每个数出现次数,创建对应计数数组,再根据计数重建有序数组,时间复杂度为`O(n)`。
|
3月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
66 1
|
6月前
|
算法 搜索推荐 Shell
|
7月前
|
人工智能 搜索推荐 JavaScript
心得经验总结:排序算法:插入排序法(直接插入法和希尔排序法)
心得经验总结:排序算法:插入排序法(直接插入法和希尔排序法)
56 0
|
7月前
|
机器学习/深度学习 搜索推荐 算法
【C/排序算法】:直接插入排序和希尔排序
【C/排序算法】:直接插入排序和希尔排序
56 0
|
7月前
|
搜索推荐
排序算法---希尔排序---详解&&代码
排序算法---希尔排序---详解&&代码
|
8月前
|
存储 算法 搜索推荐
【数据结构与算法】:插入排序与希尔排序
欢迎大家来到初阶数据结构的最后一小节:排序
【数据结构与算法】:插入排序与希尔排序
|
7月前
|
算法 Shell C语言
数据结构与算法——希尔排序(引例、希尔增量序列、原始希尔排序、代码、时间复杂度、Hibbard增量序列、Sedgewick增量序列)
数据结构与算法——希尔排序(引例、希尔增量序列、原始希尔排序、代码、时间复杂度、Hibbard增量序列、Sedgewick增量序列)
92 0
|
8月前
|
搜索推荐 算法 Shell
【数据结构与算法】直接插入排序和希尔排序
【数据结构与算法】直接插入排序和希尔排序

热门文章

最新文章