本篇博客中的代码实现依然采用Swift3.0来实现。在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找、折半查找、插值查找、Fibonacci查找,还包括数结构的二叉排序树以及平衡二叉树的构建与查找,然后还聊了哈希表的构建与查找。接下来的几篇博客中我们就集中的聊一下常见的集中排序方式,并并给出相应的时间复杂度。本篇博客我们将会详细的介绍冒泡排序、插入排序、希尔排序以及选择排序,下篇博客将继续介绍堆排序、归并排序以及快速排序的相关内容。当然上述内容的代码实现我们依然采用Swift面向对象语言来实现。

本篇博客的思路与以往博客的思路一直,先分析每种排序的规则,然后给出原理示意图,最后根据示意图给出相应的代码实现。编程这东西,只要是思路清晰,给出相应的代码实现并不困难,本篇是使用Swift语言来实现的,如果你对Swift语言不熟悉,你可以选择其他你熟悉的语言来实现。虽然语言不同,但是思路和方法都是一样的。废话少说,开始今天博客的主题。

一、排序协议的定义

在博客的开头的,我们先给出排序协议的定义。因为我们本篇博客含有多种排序方式,为了使每种排序方法对外调用方式一致,我们需要定义一个排序的相关协议。所有排序的相关类都必须遵循该协议,让此协议来定义具体的排序类对外的调用方式。

下方的SortType协议就是我们定义的排序类型的协议。其中的sort()方法是遵循该协议的类必须要实现的方法。sort()函数的参数是一个含有Int类型的数组,该数组就是要排序的数组。该方法的返回值是已经被排好序的数组。具体代码如下所示。

  

 二、冒泡排序

接下来我们来聊一下冒泡排序,冒泡排序就像其名字一样,还是比较生动的。在冒泡排序过程中会将数组分成两部分,一部分是已经有序的数列,一部分是无序的数列。无序数列中不断的将其中最小的值往有序序列中冒泡,泡冒完后,我们的序列就创建好了。本部分,我们将要给出冒泡排序的示意图,已经相应的代码实现。

1、冒泡排序示意图

下方就是第一轮冒泡的具体过程,我们要对[62, 88, 58, 47, 62, 35, 73, 51, 99, 37, 93]序列进行冒泡排序。经过第一轮的冒泡后,该序列中最小的值35被冒到了数列的最前方。因为冒泡的过程是挨个比较已经交换的过程。元素状态我们的泡中是93,93与前一个值37进行比较,发现37要小于93,所以将泡中的值改成37,并往前移动。紧接着37在与前面的99比较,发现泡中的值要小,此刻不更新泡中的值并往前移动一个格。以此类推,无序序列中最小的值就会被冒到序列的起始位置。

每轮冒泡都会从无序序列中冒出那个最小的值,所以经过n(数列有n个值)次冒泡后,我们的数列就是有序的了。冒泡过程中的比较与交换的具体步骤如下所示:

  

2.代码实现

根据上述示意图,我们很容易给出下方的代码。下方就是冒泡排序的代码,BubbleSort这个类就是冒泡排序所对应的类,此类为了统一对外的调用方式,所以必须要遵循我们上一部分所定义的SortType协议。

说白了,冒泡的过程就是不断比较和交换的过程,如果前一个值比后一个值要大,那么就要进行交换了

  

3、运行结果

下方代码就是上述BubbleSort类所运行的具体结果。排序结果中详细的打印了冒泡排序在每一轮冒泡中每一步要做的事情,具体如下所示。

  

  

三、插入排序

插入排序算是比较好理解的排序方式,插入排序也是将要排序的数列分为两部分,前半部分是已经排好序的,后半部分则是无序的。插入排序中的插入是指“取出无序数列中第一个值,插入到有序数列中相应的位置”。其实这个插入过程也是不断比较和交换的过程。

1、插入排序示意图

下方就是插入排序的示意图,红色部分是有序数列,而绿色部分是无序数列。每一轮插入都会取出无序数列中的第一个元素插入到有序数列中,这个插入的过程其实就是一个比较交换的过程,如果要插入的值比前面的值要小,就要交换,直到不能交换为止。下方就是插入排序的过程。具体如下所示:

  

2、代码实现

有了上述的示意图,给出相应的代码实现并不困难。代码的核心思想就是通过循序不断从无序数列中取出值,然后循环遍历有序数列寻找合适的插入点。在下方中有两个循环嵌套,外层循环负责不断从无序序列中取值,然后通过内层循环将外层循环取出的值插入到有序数列中相应的位置,具体如下代码所示:

  

3、运行结果

下方是运行结果的截图,该运行结果其实就是插入排序的详细过程。每一轮插入的过程就是有序序列增加,无序序列减少的过程。下方就是插入过程的详细信息。

  

四、希尔排序

因为这个排序是一个叫希尔的人发明的,所以就叫希尔排序了。其实希尔排序是插入排序的升级版, 希尔排序根据其排序的特点又叫做缩小增量排序。希尔排序的大体步骤就是先将无序序列按照一定的步长(增量)分为几组,分别将这几组中的数据通过插入排序的方式将其进行排序。然后缩小步长(增量)分组,然后将组内的数据再次进行排序。知道增量为1位置。经过上述这些步骤,我们的序列就是有序的了。其实上述的插入排序就是增量为1的希尔排序,下方会给出相应的示意图以及代码实现。

1.希尔排序示意图

下方就是希尔排序的详细步骤,接下来我们将会对每一步进行详细的解说。如下所示:

  • (1)、首先按照增量进行分组,因为我们要排序的数列有11个,增量初始值是step = 11 / 2 = 5。也就是按照增量为5的步长对数组进行分组。在下方第一步中就是按照增量为5的方式进行分组的。我们将为一组的元素使用直线进行相连,分完组后,我们就将组内中的元素进行插入排序。

  • (2)、将上一步使用的增量进行缩小,也就是本步骤的step = 5 / 2 = 2。 本部分,就要按照2的增量将上一步排序后的数组进行分组,然后再次将每个组内的数据进行插入排序。

  • (3)、再次缩小增量,此刻step = 2 / 2 = 1, 当增量为1时,其实就是我们上一部分的插入排序。将整个数组进行插入排序,然后我们的数组就是有序的了。

具体示意图如下所示:

  

2、希尔排序的代码实现

根据上述的步骤,然后再结合着插入排序的代码,给出希尔排序相应的代码并不困难。就是将插入排序的步长从1修改成我们每次生成的步长即可,每次增量排序完毕后,我们要对增量按照相应的规则进行缩小即可。下方就是希尔排序的代码实现。

在下方代码中,最外层循环负责增量的生成和缩减,里边的双重循环就是我们之前我们插入排序的代码,不步长要使用我们希尔排序生成的step,具体代码如下所示:

  

3、运行结果

下方就是Shell排序的运行结果,从下方结果中我们不难看出增量是逐渐减小的。下方的输出结果结合着本部分第一部分的示意图看更为直观一些。

  

 五、选择排序

接下来来聊聊选择排序,选择排序也是比较好理解的。在选择排序过程中,数组仍然被分作有序和无序两部分。而选择排序中的“选择”是指不断从无序序列中选择最小的值放入到有序序列的最后的位置,换句话说就是从现有的无序序列中找出那个最小的值,然后与无序序列的第一个值进行交换,然后缩小无序序列的范围即可。因为有序序列的最后一个值与无序序列的第一个值紧挨着,交换后,这个无序序列中的第一个值就成了有序序列的最后一个值。重复这个选择的过程,我们的数组就会变得有序。下方将会给出详细的示意图以及相应的代码实现。

 

1.选择排序示意图 

下方就是简单选择排序的部分步骤,只需要重复下方的步骤就可以通过选择排序将我们的数组变成有序的序列。下方是对下方步骤的详细介绍:

  • 初识状态下,我们整个数组就是无序的,从整个数组中我们找到了最小的元素35,其下标为5。然后将35与无序序列第一个元素62进行交换。交换后,有序序列中就有了一个值:35,而无序序列中就少了一个值:35。无序序列中的第一个值也就是变成了88。

  • 再次从无序序列中选择那个最小的值。于是乎我们又找到了37,然后让37与88进行交换。有序序列就成了{35,37}。

  • 再次从无序序列中选择最小的那个值,经过查找我们找到了47,然后将47与58进行交换。此刻有序序列就成了{35, 37, 47}。

  • 重复的从无序序列中选择最小的值进行交换......

  

2.选择排序具体代码实现

有了上述选择的示意图,根据思路敲代码。下方就是选择排序的具体代码实现。代码实现起来还是比较简单的,就是通过一个循环,不断的从无序序列中选出那个最小的值与无序序列中的第一个值进行交换即可。下方第一个框中就是从无序序列中查找最小的那个值的代码,第二个框就是交换的过程。如下所示:

  

3、运行结果

与上几个排序一样,我们输出的运行结果就是选择排序的详细的过程。下方就是选择排序的详细过程,如下所示:

  

六、测试用例

在博客要结尾的部分,我们仍然会给出本篇博客所使用的测试用例。下方就是本篇博客所使用的测试用例。上述的运行结果就是下方我们测试用例的输出结果。虽然输出的结果不同,但是我们用的都是一个测试函数,只是传入的排序对象不同。这也就是我们在程序的第一部分为什么要给出相应的协议定义的原因。测试用例如下所示:

  

本篇博客所涉及的所有代码都会在github上进行分享,下方是分享地址。后面会继续更新其他排序算法。

github代码分享地址: https://github.com/lizelu/DataStruct-Swift/tree/master/AllKindsOfSort

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px "Hannotate SC" }

算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)的更多相关文章

  1. 几种常见排序算法之Java实现(插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序)

    排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 稳定度(稳定性)一个排序算法是稳定的,就是当有两个相等记录的关 ...

  2. 跳跃空间(链表)排序 选择排序(selection sort),插入排序(insertion sort)

    跳跃空间(链表)排序 选择排序(selection sort),插入排序(insertion sort) 选择排序(selection sort) 算法原理:有一筐苹果,先挑出最大的一个放在最后,然后 ...

  3. 必须知道的八大种排序算法【java实现】(二) 选择排序,插入排序,希尔算法【详解】

    一.选择排序 1.基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换:然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止. 2.实例 3.算法 ...

  4. C# 冒泡排序法、插入排序法、选择排序法

    冒泡排序法 是数组等线性排列的数字从大到小或从小到大排序. 以从小到大排序为例. 数据 11, 35, 39, 30, 7, 36, 22, 13, 1, 38, 26, 18, 12, 5, 45, ...

  5. C#之快速排序 C#之插入排序 C#之选择排序 C#之冒泡排序

    C#之快速排序   算法描述 1.假定数组首位元素为“枢轴”,设定数列首位(begin)与末位(end)索引: 2.由末位索引对应元素与“枢轴”进行比较,如果末位索引对应元素大于“枢轴”元素,对末位索 ...

  6. [PHP]基本排序(冒泡排序、快速排序、选择排序、插入排序、二分法排序)

    冒泡排序: function bubbleSort($array){ $len=count($array); //该层循环控制 需要冒泡的轮数 for($i=1;$i<$len;$i++){ / ...

  7. java实现 排序算法(鸡尾酒排序&选择排序&插入排序&二分插入排序)

    1.鸡尾酒排序算法 源程序代码: package com.SuanFa; public class Cocktial {    public static void main(String[] arg ...

  8. javascript的冒泡排序, 快速排序, 选择排序, 插入排序

    冒泡排序, 最经典的排序, 把比较大的数字往后放, 和选择排序恰恰相反: <!DOCTYPE html> <html lang="en"> <head ...

  9. 2017.12.9 Java中的排序---冒泡排序、快速排序、选择排序

    //冒泡排序 public class demo{ public static void main(String[] args) { int[] sum={2,9,10,1,5,88}; System ...

随机推荐

  1. Python中的多进程与多线程(一)

    一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...

  2. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  3. 06.SQLServer性能优化之---数据库级日记监控

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 之前说了一下数据库怎么发邮件:http://www.cnblogs.com/duniti ...

  4. requests的content与text导致lxml的解析问题

    title: requests的content与text导致lxml的解析问题 date: 2015-04-29 22:49:31 categories: 经验 tags: [Python,lxml, ...

  5. 【原】AFNetworking源码阅读(三)

    [原]AFNetworking源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇的话,主要是讲了如何通过构建一个request来生成一个data tas ...

  6. Ubuntu 16.10 安装byzanz截取动态效果图工具

    1.了解byzanz截取动态效果图工具 byzanz能制作文件小,清晰的GIF动态效果图,不足就是,目前只能通过输入命令方式来录制. byzanz主要的参数选项有: -d, --duration=SE ...

  7. ASP.NET MVC5+EF6+EasyUI 后台管理系统(65)-MVC WebApi 用户验证 (1)

    系列目录 前言: WebAPI主要开放数据给手机APP,其他需要得知数据的系统,或者软件应用,所以移动端与系统的数据源往往是相通的. Web 用户的身份验证,及页面操作权限验证是B/S系统的基础功能, ...

  8. 谈谈一些有趣的CSS题目(四)-- 从倒影说起,谈谈 CSS 继承 inherit

    开本系列,讨论一些有趣的 CSS 题目,抛开实用性而言,一些题目为了拓宽一下解决问题的思路,此外,涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题中有你感觉 ...

  9. 解读发布:.NET Core RC2 and .NET Core SDK Preview 1

    先看一下 .NET Core(包含 ASP.NET Core)的路线图: Beta6: 2015年7月27日 Beta7: 2015年9月2日 Beta8: 2015年10月15日 RC1: 2015 ...

  10. PHP与API讲解(一)

    了解API: 在使用与创建自己的API之前我们需要先了解什么是API! API代表应用程序编程接口,而接口指的是一个特定的服务.一个应用程序或者其他程序的公共模块. 理解SOA(面向服务的架构):SO ...