极客算法训练笔记(五),十大经典排序之冒泡,选择,插入排序

极客算法训练笔记(五),十大经典排序之冒泡,选择,插入排序

首页卡牌对战小龙飞飞游戏更新时间:2024-04-23

排序算法衡量指标

关于排序算法的重要性我就不啰嗦了,不重要你也遇不到这篇文章。安利一个学习算法免费看动画的网站,该文的动图都来自这个网站 https://visualgo.net/zh/sorting ,感谢站长。

那么多的经典和野鸡排序算法,讲之前我们先关注一下排序算法的衡量指标:

  1. 时间复杂度
  2. 空间复杂度
  3. 最好情况
  4. 最坏情况
  5. 比较次数,交换次数
  6. 稳定性稳定性解释:比如我们有一组数据2,9,3,4,8,3,按照大小排序之后就是2,3,3,4,8,9。 这组数据里有两个3。经过某种排序算法排序之后,如果两个3的前后顺序没有改变,那我们就把这种排序算法叫作稳定的排序算法;如果前后顺序发生变化,那对应的排序算法就叫作不稳定的排序算法。为什么要关注稳定性?脱离了实际运用的数据结构是没有意义的,真正软件开发中,我们要排序的往往不是单纯的整数,而是一组对象,我们需要按照对象 的某个key来排序。比如说,我们现在要给电商交易系统中的“订单”排序。订单有两个属性,一个是下单时间,另一个是订单金额。如果我们现在有10万条订单数据,我们希望按照金额从小到大对订单数据排序。对于金额相同的订单,我们希望按照下单时间从早到晚有序。对于这样一个排序需求,我们怎么来做呢?- 直接思路:我们先按照金额对订单数据进行排序,然后,再遍历排序之后的订单数据,对于每个金额相同的小区间再按照下单时间排序。这种排序思路理解起来不难,但是实现起来会很复杂。

    - 稳定排序算法思路:这个问题可以非常简洁地解决,我们先按照下单时间给订单排序,注意是按照下单时间,不是金额。排序完成之后,我们用稳定排序算法,按照订单金额重新排序。两遍排序之后,我们得到的订单数据就是按照金额从小到大排序,金额相同的订单按照下单时间从早到晚排序的。

    - 为什么呢?
    稳定排序算法可以保持金额相同的两个对象,在排序之后的前后顺序不变。第一次排序之后,所有的订单按照下单时间从早到晚有序了。在第二次排序中,我们用的是稳定的排序算法,所以经过第二次排序之后,相同金额的订单仍然保持下单时间从早到晚有序。
  7. 十大经典排序算法江山图
  8. 是否原地(原址,就地)排序维基百科说的原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。简单理解为,允许借助几个变量,不需要额外开数组。属于原地排序的是:希尔排序、冒泡排序、插入排序、选择排序、堆排序、快速排序,他们都会有一项比较且交换操作(swap(i,j))的逻辑在其中;而合并排序,计数排序,基数排序等不是原地排序。

排序方式In-Place指的是原地排序,Out-place指的非原地排序

看了江山图之后,我们先来看江山图里混成了最底层的弟弟们,冒泡排序,选择排序和插入排序,这几个是时间复杂度最高的排序。

冒泡排序

这个排序不简单,大学里面每个学校都必教的一个排序

给定一个N个元素的数组,冒泡法排序将:

  1. 比较一对相邻元素(a,b);
  2. 如果元素大小关系不正确,交换这两个数;
  3. 重复步骤1和2,直到我们到达数组的末尾(最后一对是第(N-2)和(N-1)项,因为我们的数组从零开始)
  4. 第一次循环比较结束,最大的元素将在最后的位置。 然后我们将N减少1,并重复步骤1,直到N = 1。

public class BubbleSort { public static int[] bubbleSort(int[] arr) { if (arr == null || arr.length < 2) { return arr; } int n = arr.length; // 第一层循环,每循环一次,排好一个元素,在最右边 for (int i = 0; i < n; i ) { // 第二层循环,到右边第一个没有排序过元素地方结束,进行比较交换 for (int j = 0; j < n -i - 1; j ) { // 比较,大于小于号决定是按照从大到小排还是从小到大排 if (arr[j 1] < arr[j]) { // 交换 int t = arr[j]; arr[j] = arr[j 1]; arr[j 1] = t; } } } return arr; } )

public class SelectSort { public static int[] selectSort(int[] a) { int n = a.length; // 从头开始遍历,选定某个元素待排序 for (int i = 0; i < n - 1; i ) { // 将这个元素设为最小值 int min = i; // 遍历所有未排过序的元素,从第i个元素右边开始 for (int j = i 1; j < n; j ) { // 如果元素小于当前最小值,那么最小值改为当前值 if(a[min] > a[j]) min = j; } // 以上得到了当前最小值,将当前最小值提到前面 //交换 int temp = a[i]; a[i] = a[j]; a[j] = temp; } return a; } }

下一篇写希尔,归并,快排和堆排序,还是按照这种格式,有收获的三连走起啊,欢迎关注我,我是小魔女阿甘。

插入排序选择排序

可知第二层循环是进行比较交换的核心逻辑,第一层循环用来确定排好了几个元素,决定了第二层循环的比较次数,n-i-1之所以减去一,是因为比如剩下10个元素没有排序,10个元素只有9对,需要比较九次。

欢迎大家关注我的公众号《阿甘的码路》,首发都在这里。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved