数据结构基础之排序算法二

学习算法,排序算法当然是不能少的,这次我们来学习一下基础的选择排序,冒泡排序,以及大名鼎鼎的快速排序。

选择排序

选择排序,非常好理解,就是找最小的数放到第一位,然后从第二个数开始找最小的数,放到第二个位置,然后从第三个数开始找最小的数,放到第三个位置… 。每次找最小的数,就是选择最小的数,这就是选择的含义。

看个图就明白了

第一次,找到最小的数字1,放到第一个位置上(当然原来在第一个位置的元素就交换到原来数字1的位置上了);第二次,从第二个位置也就是6开始,找到最小的数字2,放到第二个位置…

选择排序的逻辑非常简单,那么代码肯定也不复杂了

/*** 选择排序** 思路*  每一次找一个最小的值,交换放到最左边的位置上。*  重复这样找下去即可。**  时间复杂度 O(N^2)*  空间复杂度 O(n)*  稳定性    不稳定*/
public class SelectSortDemo {public static void selectSort(int[] data){if(null == data || data.length == 0 || data.length == 1){return ;}for (int i = 0; i < data.length; i++) { //int minIndex = i;           //当前这一轮中的最小值下标for (int j = i+1; j < data.length; j++) {  //内层循环,找最小的数if(data[minIndex] > data[j]){minIndex = j;}}if(minIndex != i){ //最小值,不是初始值,说明在后面有更小的值,那么进行交换//这儿用一个加减法技巧来完成两个数的交换,省下一个临时交换变量。data[i] = data[i] + data[minIndex];data[minIndex] = data[i] - data[minIndex];data[i] = data[i] - data[minIndex];}}}public static void main(String[] args) {int[] data = {2,6,3,5,4,1,0,8,7,9,2};selectSort(data);System.out.println(Arrays.toString(data));}
}

注意代码中,交换两个位置上的值,有一个小技巧就是不使用辅助变量也可以完成的,你可以get一下。

选择的排序的时间复杂度显然是n^2,和插入排序一样,胜在简单,但是因为其不稳定的特性,实际使用的较少。

冒泡排序

冒泡排序,一次循环会找出一个最大数放到最后,就像水泡从水底往上冒出来一样,这也是冒泡排序的名称由来。它的基本逻辑是,挨着的两个元素比较,大的就就交换到后面,依次不断的往后比较,一轮下来,最大的那个数就会跑到最后面去。

同样,看图说话

代码实现也比较容易:

/*** 冒泡排序**  思路:*  从前到后,依次两两比较,如果前面大于后面的元素,将两个元素进行交换,完成一轮比较之后,最大的值就会放到最后*  重复这个过程,直到剩下最左边最后一个元素。*  就像气泡从水底往上冒出来一样,这也是冒泡排序的名称由来。** 时间复杂度 O(N^2)* 空间复杂度 O(n)* 稳定性    稳定(实现中在与有序段比较时,只有小于才发生交换)**/
public class BubbleSortDemo {public static void bubbleSort(int[] data){if(null == data || data.length == 0 || data.length == 1){return ;}for (int i = data.length; i > 0; i--) {for (int j = 0; j < i-1; j++) {if(data[j+1] < data[j] ){ // 后一个元素小于前一个元素,发生交换int temp = data[j];data[j] = data[j+1];data[j+1] = temp;}}}}public static void main(String[] args) {int[] data = {2,6,3,5,4,1,7,0,9};bubbleSort(data);System.out.println(Arrays.toString(data));}
}

时间复杂度显然是n^2,也是比较简单。

快速排序

快速排序,听名字就知道它很快,那么我们就来分析分析,它有多快,是如何快起来的?

快速排序同样使用了分治的思想,但和归并不一样的是,它在拆分时,并不是二分,而是选定一个基准值,将小于这个基准值的拆到一段,大于基准值的拆到一段;然后小的这一段再重新选择基准值,小于新基准值的再拆分一段,大于新基准值的拆为一段;重复这样下去,直到不用再拆为止。因为每次拆分之前,小于基准和大于基准的就分开了,那么最后拆出来的就已经是有序的了,因此它只有递归的递的过程,没有归的过程,不就是个尾递归嘛。

不说楞个多,上图才是正事

快排的核心思想相信你应该有所了解了,其中讲到选定一个基准值,将小于这个基准值的拆到一段,大于基准值的拆到一段,这个操作有很多种实现方式,上图就提供一种思路:

  1. 从基准值后面的元素中找出第一个比他小的元素,和基准值交换
  2. 从前面找出第一个比它大的元素,和基准值交换
  3. 重复1和2,直到遍历完这一段元素。

上一盘代码,你说香不香

/*** 快速排序**  思路: 拆分,递归*  选择一个基准值,并通过比较和交换,将所有小于基准值的放到它的左边,将所有大于基准值的放到它的右边。*  (具体实现方式,可以先从基准值的右边找比他小的,和它交换; 然后从左边找比它大的,再和它交换;*  然后再右边,再左边,做完一轮之后,就能实现基准值的左边都是小于它的,右边都是大于它的)。*  现在就可以将数组拆分为3个部分(如果基准值最大/最小,那会是2个部分),左边的子数组,基准值,右边的子数组,*  接下来迭代对左、右子数组进行一样的操作(选基准值,比较交换),直到拆分到不能再拆分为止(小于等于2个元素即可)**  时间复杂度 O(nlogn)*  空间复杂度 O(n)*  稳定性    不稳定(因为以基准值进行交换,会打乱原本相同值的前后顺序)*/
public class QuickSortDemo {public static void quickSort(int[] data){if(null == data || data.length == 0 || data.length == 1){return ;}recursionSort(data, 0, data.length-1);}public static void recursionSort(int[] data,  int left, int right){//递归终止条件if(left>=right){return;}int base = left; //选定基准值,这儿简单起见,选左边第一个int ll = left;  //遍历左边时使用的指针int rr = right; //遍历右边时使用的指针while(ll < rr){//从右边往左边找,找到一个比base小的值时,交换while(ll < rr) {if (data[rr] < data[base]) {int temp = data[rr];data[rr] = data[base];data[base] = temp;base = rr;rr--;break;}rr--;}//从左边往右边找,找到一个比base大的值时,交换while(ll < rr) {if (data[ll] > data[base]) {int temp = data[ll];data[ll] = data[base];data[base] = temp;base = ll;ll++;break;}ll++;}}recursionSort(data, left, base-1); //左半边递归recursionSort(data, base+1, right); //右半边递归}public static void main(String[] args) {int[] data = {2,6,3,5,4,1,0,8,7,9,2};quickSort(data);System.out.println(Arrays.toString(data));}
}

应该可以发现,快排中,基准值的选择还是比较重要的,选得好,那么拆分就比较均匀,树的深度也就越小,当然效率也就越高了,所以优化快排的思路就在基准值的选取上,你可以暂开。

到此呢,我们学习了6种排序算法了,来综合比较下他们:

排序名称 时间复杂度 是否稳定 额外空间开销
插入排序 O(n^2) 稳定 O(1)
冒泡排序 O(n^2) 稳定 O(1)
选择排序 O(n^2) 不稳定 O(1)
希尔排序 O(n^2) 不稳定 O(1)
归并排序 O(nlogn) 稳定 O(n)
快速排序 O(nlogn) 不稳定 O(1)

这么多种排序算法我们究竟应该怎么选择呢?

1.分析场景:稳定还是不稳定

2.数据量:数据量小的时候选什么?比如就50个数,优先选插入。

综上所述,没有一个固定的排序算法,都是要根据情况分析的。当然,你不想去做过多选择,那么就上归并或者快排吧,至少在数据量大的时候,系统不会崩盘。

最后今天的几种排序算法,你可以在一个堪称神器的网站上观察排序算法运行的过程。

可视化动态排序演示:https://www.cs.usfca.edu/~galles/visualization/ComparisonSort.html

学了排序算法,来个思考题,对200W学生的成绩排序,成绩从0到999.99(两位小数),要求效率要高的。

(也许根本不是用排序来做哦,还记得年龄问题吗?扩展一下就可以变成计数排序了)

数据结构和算法之五:排序算法二相关推荐

  1. 数据结构排序算法实验报告_[数据结构与算法系列]排序算法(二)

    我的上一篇文章向大家介绍了排序算法中的冒泡排序.插入排序和选择排序.它们都是平均时间复杂度为 O(n^2) 的排序算法,同时还为大家讲解了什么是原地排序和什么是排序的稳定性.下图是这三种算法的比较,不 ...

  2. 数据结构与算法之排序算法

    数据结构与算法之排序算法 排序算法的介绍 ​ 排序也称排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排序的过程. 排序的分类 1)内部排序:指将需要处理的数据都加载到内部 ...

  3. 大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 21

    大话数据结构读书笔记艾提拉总结 查找算法 和排序算法比较好 第1章数据结构绪论 1 第2章算法 17 第3章线性表 41 第4章栈与队列 87 第5章串 123 第6章树 149 第7章图 211 第 ...

  4. python结构排序_Python数据结构(七)排序算法 上

    Python数据结构(七)排序算法 上 上回: 本文的重点不是代码,而是带着大家分析每一个排序算法背后的思想以及使用到的数据结构.很多时候不是我们想不出算法该如何去写,而是题目并没有指定特定的数据结构 ...

  5. 在Object-C中学习数据结构与算法之排序算法

    笔者在学习数据结构与算法时,尝试着将排序算法以动画的形式呈现出来更加方便理解记忆,本文配合Demo 在Object-C中学习数据结构与算法之排序算法阅读更佳. 目录 选择排序 冒泡排序 插入排序 快速 ...

  6. c++ 二维数组 排序_【算法】排序算法之计数排序

    前几回,我们已经对[算法]排序算法之冒泡排序.[算法]排序算法之插入排序.[算法]排序算法之希尔排序.[算法]排序算法之选择排序.[算法]排序算法之快速排序.[算法]排序算法之归并排序.[算法]排序算 ...

  7. 数据结构与算法(三) 排序算法(代码示例)

    数据结构与算法三 排序算法 1. 选择排序 2. 插入排序 3. 冒泡排序 4. 归并排序 5. 快速排序 6. 希尔排序 7. 堆排序 总结 1. 选择排序 选择排序的基本原理: 对于未排序的一组记 ...

  8. 查找算法与排序算法之Python实现

    查找算法与排序算法 查找算法 顺序查找 二分查找 排序算法 冒泡排序 选择排序 简单选择排序 选择排序 插入排序 快速排序 堆排序 堆排序topk问题 归并排序 希尔排序 计数排序 桶排序 基数排序 ...

  9. 算法---比较排序算法

    在大批量的刷题之前,做好前期的准备工作,首先明白了时间复杂度和空间复杂度的计算方法,这个在我的上一篇博文里有提到,然后对经典排序算法做一个全面了解,2017.7.13,本文大部分内容引自http:// ...

  10. 十大经典排序算法-选择排序算法详解

    十大经典排序算法 十大经典排序算法-冒泡排序算法详解 十大经典排序算法-选择排序算法详解 十大经典排序算法-插入排序算法详解 十大经典排序算法-希尔排序算法详解 十大经典排序算法-快速排序算法详解 十 ...

最新文章

  1. 空间点像素索引(二)
  2. eclipse 插件扩展新建java页面_java-Eclipse插件-弹出菜单扩展
  3. Java常用的5大框架介绍!
  4. 采用预取(Prefetch)来加速你的网站(转)
  5. catch Floating point expection
  6. 【批处理DOS-CMD命令-汇总和小结】-输出/显示命令——echo
  7. 5.1数学建模与MATLAB--层次分析法(评价类问题)
  8. 《SEM长尾搜索营销策略解密》一一2.11 向传统行业致敬
  9. 计算机主机配置一般有机箱主板cpu,电脑配置参数详解教程
  10. 奇葩报错之返回值为 -1073741515 (0xc0000135) ‘未找到依赖 dll‘
  11. 解决qt.qpa.plugin: Could not load the Qt platform plugin “xcb“ in ““ even though it was found.问题
  12. Python-字符版gif图
  13. 8. 关于打分函数F1分数 TPR PPV等
  14. 计算机围棋发展史,围棋变迁史
  15. 查找和排序算法的学生成绩分析实验
  16. thc-ssl-dos攻击https站点
  17. 写好SCI论文的语言技巧 --- 学术英语的表达 ---- 主动与被动语态如何取舍
  18. commons-lang3:BooleanUtils
  19. HANDSFREE小车搭载VX-11雷达配置方法
  20. Zemax学习笔记——光纤耦合输出光束整形(圆光斑)

热门文章

  1. 牛客-taotao要吃鸡
  2. 快速理解决策树 bootstrap,bagging,boosting,online boosting-五个概念
  3. 肚 脐 敷 药 治 病 法
  4. sql decode函数
  5. 推荐系统特殊领域——音乐推荐
  6. [教程] Mac OS X Lion Spotlight 优化指南
  7. 万物数字化的时代,开发者的“变”与“不变”
  8. blender产品设计及场景制作
  9. 一块钱买一瓶水,两个空瓶换一瓶水,三个瓶盖换一瓶水,现在有20块钱,一共可以喝多少瓶水?(方法2)
  10. 如何查看mysql的版本情况?