数据结构(初阶)—— 排序算法(上)(1)

简介: 数据结构(初阶)—— 排序算法(上)(1)

前言

      排序在我们日常生活中很常见,如:打扑克牌、商品的销量、价格、好评度等都需要用到排序;排序目的在于让我们跟容易对事物一目了然;所以掌握好排序也是非常有必要的;接下来我们介绍排序算法的前两个:插入排序和选择排序;

一、直接插入排序


什么是直接插入排序?

       相信大家都完过扑克牌,摸得一手好牌(如果全是炸弹^-^)牌堪比人上人呀;我们从开始摸第一张牌起其后摸得所有牌,都需要插入到相应的位置,让自己手中的牌按升序或降序的排列方式组合起来;

1ecd1b2606ed46e9956a89f231c9802c.png

1.动图演示

对于一个随机组合的数组[ 6, 2, 10, 3, 9, 4, 8, 5, 1, 7 ] ,我们如何利用直接插入排序,将其排列成升序或降序的排列方式呢?


image.gif

看过了动图,那么如何操作实现呢?

1ecd1b2606ed46e9956a89f231c9802c.png


2.代码实现

// 插入排序
void InsertSort(int* a, int n)
{
  assert(a);
  for (int i = 0; i < n - 1; i++)
  {
    //将x插入【0,end】有序区间
    int end = i;
    int x = a[end + 1];
    while (end >= 0)
    {
      if (a[end] > x)
      {
        a[end + 1] = a[end];//将前一个数向后挪动
        --end;
      }
      else
      {
        break;
      }
    }
    a[end + 1] = x;
  }
}

二、希尔排序

       希尔排序,顾名思义就是有一个叫希尔的大佬想出的排序算法;也被称为"缩小增量排序"它的本质还是插入排序,是在直接插入排序算法的基础上进行改进;他是如何一步一步改进的呢?

1.希尔大佬来告诉你他是怎么想的?

1ecd1b2606ed46e9956a89f231c9802c.png

1ecd1b2606ed46e9956a89f231c9802c.png

1ecd1b2606ed46e9956a89f231c9802c.png

2.如何实现单趟的分组预排(含动态演示)

我们以间距(gap)为3为例;来对这10个数据进行第一组的与排序;

image.gif


从上面的动图可以看出,本质思想还是直接插入;

void ShellSort(int* a, int n)
{ 
int gap = 3;
  for (int i = 0; i < n - gap; i+=gap)
  {
      int end = i;
    int x = a[end + gap];
    while (end >= 0)
    {
      if (a[end] > x)
      {
        a[end + gap] = a[end];
        end -= gap;
      }
      else
      {
        break;
      }
    }
    a[end + gap] = x;
  }
}

60a6bcefe26f4b118e50f46e4d0afd1d.png

3. 多组预排序的方法(含动态演示)

方法1:

在单趟与排序的基础上外面套一层循环,一共gap组,那就循环gap次;

动图演示:

20201204182323419.gif

方法2:

在方法1的基础上做了一些改进,它不再是先排完第一组再排第二组,再排第三组;它让三组同时开始预排;

动图演示:

20210505110855951.gif

上述两种方法都是不错的,方法2并没有质的提升,但是在量上略微提升了一些;

代码实现

// 希尔排序
void ShellSort(int* a, int n)
{ 
  //多组一锅炖1
  int gap = 3;
  for (int j = 0; j < gap; j++)
  {
    for (int i = 0; i < n - gap; i+=gap)
    {
      int end = i;
      int x = a[end + gap];
      while (end >= 0)
      {
        if (a[end] > x)
        {
          a[end + gap] = a[end];
          end -= gap;
        }
        else
        {
          break;
        }
      }
      a[end + gap] = x;
    }
  }
  //多组一锅炖2
    int gap = 3;
  for (int i = 0; i < n - gap; ++i)
  {
    int end = i;
    int x = a[end + gap];
    while (end >= 0)
    {
      if (a[end] < x)
      {
        a[end + gap] = a[end];
        end -= gap;
      }
      else
      {
        break;
      }
    }
    a[end + gap] = x;
  }
}

4. 希尔排序实现

       从本段第一点的介绍,希尔大佬提出先将数组以间距为3分为3组数据进行预排,再以间距为2将数组分为2组进行预排;最后再以间距为1(即直接插入排序)进行最后的一次排序;达到升序或降序的排列组合;

// 希尔排序
void ShellSort(int* a, int n)
{
  int gap = n;
  while (gap > 1)
  {
    //gap = gap / 2;
    gap = gap / 3 + 1;
    for (int i = 0; i < n - gap; i++)
    {
      int end = i;
      int x = a[end + gap];
      while (end >= 0)
      {
        if (a[end] > x)
        {
          a[end + gap] = a[end];
          end -= gap;
        }
        else
        {
          break;
        }
      }
      a[end + gap] = x;
    }
  }
}


阅读本段至此,我们可以发现一些问题?


1.gap越大,预排越快,预排后越不接近有序;


       间距越大,意味着越小的数字能够很快的跳的前面来,越大的数字能很快的跳到后面去;虽然预排比较快,但是整体看不出来有序;

2.gap越小,预排越慢,预排后越接近有序;


       间距越小,意味着它每部分的数据都接近于有序,整体相对有序,但是预排相对比较慢;

3.gap == 1 ,就是直接插入排序;


       当间距在发生变化时,不断进行预排,每次都在向有序靠近,知道最后间距变化为1时,就能将整个数组排列完成;


一般gap是如何确定呢?


       起初,希尔大佬认为gap=n/2、gap=gap/2直到gap=1;后来Knuth提出取gap=gap/3+1.还有人认为取奇数为好,也有人提出取gap互质为好。无论哪一种主张都没有得到证明;小伙伴就可以以 gap=gap/2 或 gap=gap/3+1 来取;需要强调的是 gap=gap/3+1


这里为什么需要加1呢?当有N个数据时且N为偶数时,除到最后是,gap就为0了,我们需要最后一次达到gap=1,去进行直接插入排序,所以这里加1的目的就在于此;




目录
相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
55 1
|
3月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
102 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
|
2月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
2月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
114 23
|
2月前
|
算法
数据结构之蜜蜂算法
蜜蜂算法是一种受蜜蜂觅食行为启发的优化算法,通过模拟蜜蜂的群体智能来解决优化问题。本文介绍了蜜蜂算法的基本原理、数据结构设计、核心代码实现及算法优缺点。算法通过迭代更新蜜蜂位置,逐步优化适应度,最终找到问题的最优解。代码实现了单链表结构,用于管理蜜蜂节点,并通过适应度计算、节点移动等操作实现算法的核心功能。蜜蜂算法具有全局寻优能力强、参数设置简单等优点,但也存在对初始化参数敏感、计算复杂度高等缺点。
64 20
|
2月前
|
机器学习/深度学习 算法 C++
数据结构之鲸鱼算法
鲸鱼算法(Whale Optimization Algorithm,WOA)是由伊朗研究员Seyedali Mirjalili于2016年提出的一种基于群体智能的全局优化算法,灵感源自鲸鱼捕食时的群体协作行为。该算法通过模拟鲸鱼的围捕猎物和喷出气泡网的行为,结合全局搜索和局部搜索策略,有效解决了复杂问题的优化需求。其应用广泛,涵盖函数优化、机器学习、图像处理等领域。鲸鱼算法以其简单直观的特点,成为初学者友好型的优化工具,但同时也存在参数敏感、可能陷入局部最优等问题。提供的C++代码示例展示了算法的基本实现和运行过程。
61 0
|
3月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
56 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
2月前
|
算法 vr&ar 计算机视觉
数据结构之洪水填充算法(DFS)
洪水填充算法是一种基于深度优先搜索(DFS)的图像处理技术,主要用于区域填充和图像分割。通过递归或栈的方式探索图像中的连通区域并进行颜色替换。本文介绍了算法的基本原理、数据结构设计(如链表和栈)、核心代码实现及应用实例,展示了算法在图像编辑等领域的高效性和灵活性。同时,文中也讨论了算法的优缺点,如实现简单但可能存在堆栈溢出的风险等。
66 0
|
3月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
57 4

热门文章

最新文章