我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解排序算法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解排序算法

这篇文章主要讲解了“如何理解排序算法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解排序算法”吧!

排序是我们生活中经常会面对的问题,体育课的时候,老师会让我们从矮到高排列,考研录取时,成绩会按总分从高到底进行排序(考研的各位读者,你们必能收到心仪学校给你们寄来的大信封),我们网购时,有时会按销量从高到低,价格从低到高的顺序将最符合咱们预期的商品列在前面,这些都是我们生活中的例子。

排序概念:将杂乱无章的数据元素,通过一定的方法(排序算法)按关键字顺序排列的过程叫做排序。例如我们上面的销量和价格就是关键字。

排序算法的稳定性

什么是排序算法的稳定性呢?

因为我们待排序的记录序列中可能存在两个或两个以上的关键字相等的记录,排序结果可能会存在不唯一的情况,所以我们排序之后,如果相等元素之间原有的先后顺序不变。则称所用的排序方法是稳定的,反之则称之为不稳定的。见下图

如何理解排序算法

例如上图,我们的数组中有两个相同的元素 4,  我们分别用不同的排序算法对其排序,算法一排序之后,两个相同元素的相对位置没有发生改变,我们则称之为稳定的排序算法,算法二排序之后相对位置发生改变,则为不稳定的排序算法。

那排序算法的稳定性又有什么用呢?

在我们刷题中大多只是将数组进行排序,只需考虑时间复杂度,空间复杂度等指标,排序算法是否稳定,一般不进行考虑。但是在真正软件开发中排序算法的稳定性是一个特别重要的衡量指标。继续说我们刚才的例子。我们想要实现年终奖从少到多的排序,然后相同年终奖区间内的红豆数也按照从少到多进行排序。

排序算法的稳定性在这里就显得至关重要。这是为什么呢?见下图

如何理解排序算法

第一次排序之后,所有的职工按照红豆数从少到多有序。

第二次排序中,我们使用稳定的排序算法,所以经过第二次排序之后,年终奖相同的职工,仍然保持着红豆的有序(相对位置不变),红豆仍是从小到大排序。我们使用稳定的排序算法,只需要两次排序即可。

稳定排序可以让第一个关键字排序的结果服务于第二个关键字排序中数值相等的那些数。

上述情况如果我们利用不稳定的排序算法,实现这一效果是十分复杂的。

比较类和非比较类

我们根据元素是否依靠与其他元素的比较来决定元素间的相对次序。以此来区分比较类排序算法和非比较类排序算法。

内排序和外排序

内排序是在排序的整个过程中,待排序的所有记录全部被放置在内存中。外排序是由于排序的记录个数太多,不能同时放置在内存中,整个排序过程需要在内外存之间多次交换数据才能进行,常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。

对我们内排序来说,我们主要受三个方面影响,时间性能,辅助空间,算法的复杂性

时间性能

在我们的排序算法执行过程中,主要执行两种操作比较和交换,比较是排序算法最起码的操作,移动指记录从一个位置移动到另一个位置。所以我们一个高效的排序算法,应该尽可能少的比较和移动。

辅助空间

执行算法所需要的辅助空间的多少,也是来衡量排序算法性能的一个重要指标

算法的复杂度

这里的算法复杂度不是指算法的时间复杂度,而是指算法本身的复杂度,过于复杂的算法也会影响排序的性能。

下面我们一起先来复习两种简单排序算法,冒泡排序和简单选择排序,看看有没有之前忽略的东西。后面会持续连载,把常见的和实用的排序算法都进行总结。

冒泡排序(Bubble Sort)

我们在各个算法书上学习排序时,第一个估计都是冒泡排序。主要是这个排序算法思路最简单,也最容易理解,(也可能是它的名字好听,哈哈),学过的老哥们也一起来复习一下吧,我们一起深挖一下冒泡排序。

冒泡排序的基本思想是,两两比较相邻记录的关键字,如果是反序则交换,直到没有反序为止。冒泡排序一次冒泡会让至少一个元素移动到它应该在的位置,那么如果数组有  n 个元素,重复 n 次后则一定能完成排序。根据定义可知那么冒泡排序显然是一种比较类排序。

最简单的排序实现

我们先来看一下这段代码

class Solution {     public int[] sortArray(int[] nums) {         int len = nums.length;         for (int i = 0; i < len; ++i) {             for (int j = i+1; j < len; ++j) {                 if (nums[i] > nums[j]) {                     swap(nums,i,j);                 }             }         }         return nums;               }     public void swap(int[] nums,int i,int j) {         int temp = nums[i];         nums[i] = nums[j];         nums[j] = temp;     } }

我们来思考一下上面的代码,每次让关键字 nums[i] 和 nums[j] 进行比较如果 nums[i] > nums[j] 时则进行交换,这样  nums[0] 在经过一次循环后一定为最小值。

那么这段代码是冒泡排序吗?显然不是,我们冒泡排序的思想是两两比较相邻记录的关键字,注意里面有相邻记录,所以这段代码不是我们的冒泡排序,下面我们用动图来模拟一下冒泡排序的执行过程,看完之后一定可以写出正宗的冒泡排序。

冒泡排序代码

class Solution {     public int[] sortArray(int[] nums) {         int len = nums.length;         for (int i = 0; i < len; ++i) {             for (int j = 0; j < len - i - 1; ++j) {                 if (nums[j] > nums[j+1]) {                     swap(nums,j,j+1);                 }             }         }         return nums;            }     public void swap(int[] nums,int i,int j) {         int temp = nums[i];         nums[i] = nums[j];         nums[j] = temp;     } }

上图中的代码则为正宗的冒泡排序代码,但是我们是不是发现了这个问题

如何理解排序算法

我们此时数组已经完全有序了,可以直接返回,但是动图中并没有返回,而是继续执行,那我们有什么办法让其完全有序时,直接返回,不继续执行呢?

我们设想一下,我们是通过 nums[j] 和 nums[j+1]  进行比较,如果大于则进行交换,那我们设想一下,如果一个完全有序的数组,我们进行冒泡排序,每次比较发现都不用进行交换。那么如果没有发生交换则说明当前完全有序。

那我们可不可以通过一个标志位来进行判断是否发生了交换呢?当然是可以的

我们来对冒泡排序进行改进

改进的冒泡排序代码

class Solution {     public int[] sortArray (int[] nums) {         int len = nums.length;         //标志位         boolean flag = true;         //注意看 for 循环条件         for (int i = 0; i < len && flag; ++i) {             //如果没发生交换,则依旧为false,下次就会跳出循环             flag = false;             for (int j = 0; j < len - i - 1; ++j) {                 if (nums[j] > nums[j+1]) {                     swap(nums,j,j+1);                     //发生交换,则变为true,下次继续判断                     flag = true;                 }             }                   }         return nums;              }     public void swap (int[] nums,int i,int j) {         int temp = nums[i];         nums[i] = nums[j];         nums[j] = temp;     } }

这样我们就避免掉了已经有序的情况下无意义的循环判断。

时间复杂度分析

最好情况,就是要排序的表完全有序的情况下,根据改进后的代码,我们只需要一次遍历即可,只需 n -1 次比较,时间复杂度为 O(n)。

最坏情况时,即待排序表逆序的情况,则需要比较(n-1) + (n-2) +.... + 2 + 1= n*(n-1)/2  ,并等量级的交换,则时间复杂度为O(n^2)。

平均情况下,需要 n*(n-1)/4 次交换操作,比较操作大于等于交换操作,而复杂度的上限是 O(n^2),所以平均情况下的时间复杂度就是  O(n^2)。

空间复杂度分析

因为冒泡排序只是相邻元素之间的交换操作,只用到了常量级的额外空间,所以空间复杂度为 O(1)

稳定性分析

那么冒泡排序是稳定的吗?当然是稳定的,我们代码中,当 nums[j] > nums[j + 1]  时,才会进行交换,相等时不会交换,相等元素的相对位置没有改变,所以冒泡排序是稳定的。

如何理解排序算法

简单选择排序(Simple Selection Sort)

我们的冒泡排序不断进行交换,通过交换完成最终的排序,我们的简单选择排序的思想也很容易理解,主要思路就是我们每一趟在 n-i+1  个记录中选取关键字最小的记录作为有序序列的第 i 个记录,见下图

如何理解排序算法

例如上图,绿色代表已经排序的元素,红色代表未排序的元素。我们当前指针指向 4 ,则我们遍历红色元素,从中找到最小值,然后与 4  交换。我们发现选择排序执行完一次循环也至少可以将 1 个元素归位。

下面我们来看一下代码的执行过程,看过之后肯定能写出代码的。

注:我们为了更容易理解,min 值保存的是值,而不是索引,实际代码中保存的是索引

简单选择排序代码

class Solution {     public int[] sortArray(int[] nums) {          int len = nums.length;         int min = 0;         for (int i = 0; i < len; ++i) {             min = i;             //遍历找到最小值             for (int j = i + 1; j < len; ++j) {                               if (nums[min] > nums[j]) min = j;                           }             if (min != i) swap(nums,i,min);                 }         return nums;     }     public void swap (int[] nums, int i, int j) {         int temp = nums[i];         nums[i] = nums[j];         nums[j] = temp;     } }

时间复杂度分析

从简单选择排序的过程来看,他最大的特点就是交换移动元素次数相当少,这样也就节省了排序时间,简单选择和冒泡排序不一样,我们发现无论最好情况和最坏情况,元素间的比较次数是一样的,第  i 次排序,需要 n - i 次比较,n 代表元素个数,则一共需要比较(n-1) + (n-2) +.... + 2 + 1= n*(n-1)/2 次。

对于交换而言,最好情况交换 0 次,最坏情况(逆序时)交换 n - 1次。那么简单选择排序时间复杂度也为 O(n^2)  但是其交换次数远小于冒泡排序,所以其效率是好于冒泡排序的。

空间复杂度分析

由我们的动图可知,我们的简单选择排序只用到了常量级的额外空间,所以空间复杂度为 O(1)。

稳定性分析

我们思考一下,我们的简单选择排序是稳定的吗?

显然不是稳定的,因为我们需要在指针后面找到最小的值,与指针指向的值交换,见下图。

如何理解排序算法

此时我们需要从后面元素中找到最小的元素与指针指向元素交换,也就是元素 2 。但是我们交换后发现,两个相等元素 3  的相对位置发生了改变,所以简单选择排序是不稳定的排序算法。

如何理解排序算法

感谢各位的阅读,以上就是“如何理解排序算法”的内容了,经过本文的学习后,相信大家对如何理解排序算法这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解排序算法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java 数组中的冒泡排序算法如何理解

这篇文章跟大家分析一下“Java 数组中的冒泡排序算法如何理解”。内容详细易懂,对“Java 数组中的冒泡排序算法如何理解”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着小编一起深入学习“Java
2023-06-02

Java排序算法之堆排序如何实现

这篇文章主要介绍了Java排序算法之堆排序如何实现,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。二叉堆是完全二叉树或者是近似完全二叉树。二叉堆满足二个特性︰1.父结点的键值总
2023-06-21

排序算法之希尔排序法解析

目录什么是希尔排序法希尔排序法与插入排序法之间的区别与联系代码演示对比什么是希尔排序法希尔排序法(Shell Sort),也称为缩小增量排序,是一种改进的插入排序算法。它通过将待排序的元素按照一定的间隔分组,对每个分组进行插入排序,逐渐减
2023-08-08

排序算法之插入排序法解析

目录什么是插入排序法算法优化心得体会什么是插入排序法插入排序法是一种简单但有效的排序算法,其基本思想是将一个待排序的元素逐个插入到已经排好序的元素序列中,直至所有元素都被插入完成,从而得到一个有序序列。具体步骤如下:假设初始时,第一个
2023-08-08

Python排序算法之堆排序算法

堆排序看字面意思是一种排序方法,那堆是什么呢?堆是一个近似完全二叉树的结构,并同时满足堆积的性质。其实堆排序是指利用堆这种数据结构所设计的一种排序算法。
2023-01-07

Java排序算法之计数排序如何实现

这篇文章主要为大家展示了“Java排序算法之计数排序如何实现”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java排序算法之计数排序如何实现”这篇文章吧。计数排序是非比较的排序算法,用辅助数组对
2023-06-21

Java 归并排序算法、堆排序算法实例详解

基本思想:  归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。归并排序示例:合并方法:设r[i…n]由两个有序子表r[i…m
2023-05-31

排序算法图解之Java选择排序

选择排序的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。本文通过图片和示例介绍了选择排序,需要的可以参考一下
2022-11-13

排序算法图解之Java插入排序

插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。本文通过图片合示例讲解了插入排序的实现,需要的可以了解一下
2022-11-13

排序算法图解之Java希尔排序

希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法,其也是一种特殊的插入排序,即将简单的插入排序进行改进后的一个更加高效的版本,也称缩小增量排序。本文通过图片和示例讲解了希尔排序的实现,需要的可以了解一下
2022-11-13

Java如何用“自然排序”算法对数组排序

自然排序算法可以按人类阅读顺序对数组排序,它考虑数字和非数字字符。在Java中,可以使用Comparator.naturalOrder()实现自然排序,只需将数组传递给Collections.sort()方法即可。
Java如何用“自然排序”算法对数组排序
2024-04-02

PHP如何用“自然排序”算法对数组排序

PHP中的自然排序算法可对字符串数组进行排序,并以人类可读的方式将数字和字母按顺序排列。natsort()函数实现此算法,优先考虑数字大小,再按字母顺序排序。自定义比较函数允许创建自定义排序规则。NSort扩展提供更多选项和功能,包括对字符串、数字和日期进行自然排序。虽然自然排序比简单排序算法更复杂,但对于包含混合数据的数组非常有用。
PHP如何用“自然排序”算法对数组排序
2024-04-02

编程热搜

目录