冒泡排序(Bubble Sort):

很多人听到排序第一个想到的应该就是冒泡排序了。也确实,冒泡排序的想法非常的简单:大的东西沉底,汽泡上升。基于这种思想,我们可以获得第一个版本的冒泡:

public static void sort1(int[] array) {for (int i = 0; i < array.length; i++) { // i为确定了几个数for (int j = 1; j < array.length - i; j++) {if (array[j - 1] > array[j]) {// 进行两元素之间的位置交换int temp = array[j - 1];array[j - 1] = array[j];array[j] = temp;}}}}

再想一想,其实有这样一种情况:如果在某一个遍历的过程中,没有发生数据交换,那其实说明了这个数组已经是有序的了:所以我们可以作一点小小的优化(虽然不经常有用):

// 升级版1// 基于一个事实,如果某一次遍历没有发生数据交换,那么排序已经完成public static void sort2(int[] array) {boolean complete = false;for (int i = 0; i < array.length && !complete; i++) {complete = true; // 假设已经完成了for (int j = 1; j < array.length - i; j++) {if (array[j - 1] > array[j]) {complete = false;int temp = array[j - 1];array[j - 1] = array[j];array[j] = temp;}}}}

这样在应对某些比较特殊的情况下,会有一定的效果。

再来想想这样一个事实:最后产生交换的位置之后的元素是有序的。想像一下,如果一个数组只是前半部分的元素是无序的,那么我们实际上只需要遍历到无序的位置即可,其实我们上前面的算法中array.length – i这一步已经是做了类似的工作,因为我们知道后面已经有i个元素是有序的了。所以我们可以得到第三个版本的冒泡:

// 升级版2// 基于这样一个事实,如果最后的数据交换位置之后的元素是有序的// 所以,这个也是基于版本1的再一次加强public static void sort3(int[] array) {int flag = array.length; // 用于标识元素的最后的位置while (flag != 0) { // 为0说明没有发生数据的交换int last = flag;flag = 0;for (int j = 1; j < last; j++) {if (array[j - 1] > array[j]) {flag = j;int temp = array[j - 1];array[j - 1] = array[j];array[j] = temp;}}}}

选择排序(Selection Sort):

选择排序也是比较好理解的,每次从左到右扫描一次,可以得到最大的(或最小的)元素的下标,然后我们再把它与数组末尾(或者开头)的元素进行交换,这样每一次都可以找到一个最大的。实现起来也是很简单的:

// 每次从中选出最小的元素,只进行一次交换// 相比冒泡,大大减少了元素的交换次数public static void sort(int[] array) {for (int i = 0; i < array.length; i++) { // 确定了多少个元素int min = i; // 每次都默认第一个是最小的for (int j = i + 1; j < array.length; j++) {if (array[min] > array[j]) {min = j;}}int temp = array[min];array[min] = array[i];array[i] = temp;}}

直接插入排序(Insertion Sort):

直接插入排序的思路有点类似于我们平时打牌时整理时的方法,比如我整理牌的方式是,右边选择,然后插入到左边已经整理好的牌中。

直接插入排序也是这样:将要排序的元素分为有序区和无序区。每次从无序区拿出一个元素,然后在有序区找到自己的位置,强势插入。

public static void sort(int[] array) {for (int i = 1; i < array.length; i++) { // 默认第一个是有序的int temp = array[i]; // 拿出要插入的数据int j = i;// 寻找插入位置while (j > 0 && temp < array[j - 1]) {array[j] = array[j - 1];j--;}array[j] = temp;}}

对于直接插入排序来说,经常用到一个“优化”就是使用数组的第0个元素来放置要插入的数据,这样做有一个好处就是不用每次都去检查j指针是否小于0。理论上可以节省点时间。

另一种优化就是可以在查找插入位置的时候可以通过二分查找来实现,也有一定的作用。

接下来看一下这三个算法的PK情况,为了加强对比我们找到了Java类库中的Arrays.sort()这个方法来参与PK,测试数据是50000个0到500000的整数。使用的是System.currentTimeMillis()这个方法来计时:

某几次结果如下:

性能差别如此之大!显然,这三个排序算法都“弱暴了”。

接下来来看看今天的第一个高级一点的算法,也就是传说中第一批被证明是突破了N的平方运行时间的排序算法。

希尔排序(Shell Sort):

先来看看具体的程序:

public static void sort(int[] array) {for (int step = array.length / 2; step > 0; step /= 2) {for (int i = step; i < array.length; i++) {int temp = array[i];int j = i;while (j >= step && temp < array[j - step]) {array[j] = array[j - step];j -= step;}array[j] = temp;}}}

这~~~看起来是如此简单的代码。很难想像它有什么牛X之处。我还记得当时这个算法真是把我给纠结了很久,从代码上看,它有两个for循环嵌套,里面还有一个while循环。看起来时间复杂度很像是N的三次方吧。

再有,当step为1的时候,看看,是不是和直接插入排序的代码是一模一样的。那这个算法怎么可能会快啊!

希尔排序有时被叫做缩减增量排序(diminishing increment sort),使用一个序列h1,h2,h3……这样一个增量序列。只要h1=1时,任何增量序列都是可以的。但有些可能更好。对于希尔排序为什么会比直接插入排序快的原因,我们可以来看一个比较极端的例子:

假如对于一个数组{8,7,6,5,4,3,2,1}以从小到大的顺序来排。直接插入排序显然是很悲剧的了。

它的每次排序结果是这样的:

7, 8, 6, 5, 4, 3, 2, 1

6, 7, 8, 5, 4, 3, 2, 1

5, 6, 7, 8, 4, 3, 2, 1

4, 5, 6, 7, 8, 3, 2, 1

3, 4, 5, 6, 7, 8, 2, 1

2, 3, 4, 5, 6, 7, 8, 1

1, 2, 3, 4, 5, 6, 7, 8

然后我们来看看Shell排序会怎样处理,一开始步长为4

数组分为8, 7, 6, 5和4, 3, 2, 1

首先是7和4进行比较,交换位置。

变成了4, 7, 6, 5和8, 3, 2, 1

同理7和3,6和2,5和1也是样的,所以当步长为4时的结果是:

4, 3, 2, 1, 8, 7, 6, 5

可以看到,大的数都在后边了。

接下来的步长为2

这一步过程就多了很多:

一开始是4和2进行比较,交换,得到:

2, 3, 4, 1, 8, 7, 6, 5

3和1比较,交换,得到:

2, 1, 4, 3, 8, 7, 6, 5

接下来是4和8,3和7,这两个比较没有元素交换。接下来8和6,7和5就需要交换了。所以步长为2时的结果就是:

2, 1, 4, 3, 6, 5, 8, 7

可以明显地感觉到,数组变得“基本有序”了。

接下来的步长1,变成了直接插入排序。手动模拟一下就可以发现,元素的交换次数只有四次!这是相当可观的。也由此我们可以得到一个基本的事实:对于基本有序的数组,使用直接插入排序的效率是很高的!

那回到我们一开始的问题,希尔排序为什么会快?

首先说明一下,我上边的例子是极端的,不能作为正常情况来看的。但我们可以看出一点端倪:

希尔排序对元素的移动效率比直接排序要高;比如我们看第一个步长4时,直接就把4,3,2,1这四个元素的位置向前移动了4位,比起直接插入排序的一次进一步要明显高效得多。

其次,希尔每次都将数据变得“更加有序”;这一个性质相当重要,因为它利用了上一次的排序结果,在此之上让数据向“更加有序”更进一步。

最后,是一个观察的事实,就是对于“基本有序”的数组而言,直接插入排序的效率是很高的,因为只需要交换少量的元素。

好的,我们再来看看我们写的shell排序的效率怎样:这一次是两个重量级的选手,所以我们把数据量提高到500000,看看shell排序和类库中那个实现有多大的差距:

还是有差距,但比起上次那秒杀级的差距这个结果绝对可以接受了。要知道,类库个的那个算法可以用了“老长老长”的代码~~~

还有三个比较麻烦的算法。一次是讲不完的了。

先总结一下个人的一点体会:

对于排序而言,提高速度的方法明显的有两个,一个是减少数据的比较次数,一个是减少交换次数。

对于冒泡来说,它这两个方法都是最差的。

而选择排序明显就减少了交换的次数。

而直接插入排序显然在比较次数上要比选择要少,因为我们是从右至左找到合适的位置就停止。

而希尔排序相对于直接插入排序在数据交换次数上,要少得多。另外就是很好的利用了“基本有序”这个性质。在比较次数上也会少很多。

from: https://www.cnblogs.com/yjiyjige/p/3256138.html

七大排序算法的个人总结(一)相关推荐

  1. 七大排序算法大汇总(上)

    目录 一.[前言]排序的稳定性: 二.七大排序总览 三.插入排序 1.1直接插入排序 1.2直接插入排序优化版--折半插入排序: 2.希尔排序 四.选择排序 1.1选择排序 1.2进阶版选择排序 2. ...

  2. 七大排序算法的个人总结(三)

    堆排序(Heap): 要讲堆排序之前先要来复习一下完全二叉树的知识. 定义: 对一棵具有n个结点的二叉树按层序编号,如果编号为i(0 <= i <= n)的结点与同样深度的满二叉树编号为i ...

  3. 七大排序算法的个人总结(二)

    归并排序(Merge Sort): 归并排序是一个相当"稳定"的算法对于其它排序算法,比如希尔排序,快速排序和堆排序而言,这些算法有所谓的最好与最坏情况.而归并排序的时间复杂度是固 ...

  4. 七大排序算法—图文详解(插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序)

    作者:渴望力量的土狗 博客主页:渴望力量的土狗的博客主页 专栏:数据结构与算法 工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器--牛客网 点击免费注册和我一起刷题吧 目录 插入排序: ...

  5. 数据结构七大排序算法图解

    系列文章整合 排序是计算机程序设计中一个非常重要的操作,它将一个数据元素(或记录)的任意序列重新排列成一个按关键字有序的序列,在有序的序列中查找元素的效率很高,但是无序序列只能逐一查找,因此,如何进行 ...

  6. 数据结构七大排序算法图解——选择排序动图演示

    系列文章目录 四.选择排序 紧接上一篇交换排序 前言: 1.直接选择排序 思想: 例题: 代码部分: 性能分析 2.树形选择排序 思想: 例题一: 例题二: 性能分析 3.堆排序 定义: 方法: 如何 ...

  7. java七大排序算法代码

    1.冒泡排序(bubbleSort) import java.util.*; public class BubbleSort{public static void swap(int[] a,int i ...

  8. 【数据结构与算法】Java实现七大排序算法汇总

    ✨哈喽,进来的小伙伴们,你们好耶!✨

  9. java常用的7大排序算法汇总

    这段时间闲了下来,就抽了点时间总结了下java中常用的七大排序算法,希望以后可以回顾! 1.插入排序算法 插入排序的基本思想是在遍历数组的过程中,假设在序号 i 之前的元素即 [0..i-1] 都已经 ...

最新文章

  1. 网易云音乐的消息队列改造之路
  2. 临时表 DML 产生redo 问题说明
  3. 汇编中断知识之INT 1CH
  4. Mysql Incorrect string value问题解决
  5. Go语言操作MySQL
  6. http://www.appinn.com/bookmark-manager-chrome/
  7. msf各种弱口令爆破
  8. 拓扑检查中的一些问题(为啥没自相交)
  9. JAVA如何插入MySql的datetime类型
  10. 【渝粤教育】21秋期末考试基础会计10258k2
  11. 【日常学习】1月21日 学习内容
  12. unity中使用本地数据库sqlite
  13. 周志华机器学习西瓜书速记第二章绪论模型评估与选择(一)
  14. 20191216每日一句
  15. Java 技术书籍大全
  16. TokenInsight作为联盟伙伴加入CoinMarketCap的数据透明联盟(DATA) | TokenInsight
  17. 不离不弃共赴鸿蒙是什么歌,很早听过一首粤语歌,歌词好像是往往世界这么大 又可以遇到你 蛮经典的一首歌 求解答...
  18. 求一个数的平方c语言函数实现,C++中数的平方是什么函数?
  19. MATLAB与线性代数--简化阶梯矩阵
  20. Pina Colada Song现实版

热门文章

  1. spring mvc DispatcherServlet详解之一---处理请求深入解析(续)
  2. linux vi 撤销重做于前进后退--转
  3. 用sql统计vintage,滚动率,迁移率,逾期率
  4. 元宇宙和游戏赚钱的兴趣正与日俱增
  5. 元宇宙iwemeta:元宇宙催生新的行业机会,看看你能抓住哪些机遇?
  6. 基于若依框架的二次开发_浅谈若依框架
  7. 北京市:通过区块链等技术手段,实现住所申报材料无纸化
  8. linux修改容器内的mysql端口映射_修改docker容器端口映射的方法
  9. Spring-使用加密的属性文件02
  10. 在dw怎么关联css文件,重新设置Adobe Dreamweaver的文件关联解决办法