万字长文|十大基本排序,一次搞定!

大家好,我是老三,一个刷不动算法的程序员。排序算法相关题目尽管在力扣中不是很多,但是面试中动不动要手撕一下。接下来,我们看一下十大基本排序,

排序基础 排序算法的稳定性

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

当待排序记录的关键字均不相同时,排序结果是惟一的,否则排序结果不惟一[1]。

在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,该排序方法是稳定的:

若具有相同关键字的记录之间的相对次序发生变化,则称这种排序方法是不稳定的。

排序算法的稳定性

排序算法的稳定性是针对所有输入实例而言的。即在所有可能的输入实例中,只要有一个实例使得算法不满足稳定性要求,那么这种排序算法就是不稳定的。

排序的分类

按在排序过程中是否涉及数据的内、外存交换来分类,排序大致分为两类:内部排序和外部排序。

按照是否通过比较来决定元素间的相对次序,排序可以分为比较类排序和非比较类排序。

排序分类

冒泡排序 冒泡排序原理

柿子挑软的捏,先从最简单的开始。

冒泡排序有着好听的名字,也有着最好理解的思路。

冒泡排序的基本思想是,从一端到另一端遍历,两两比较相邻元素的大小,如果是反序则交换。

动图如下(来源参考[4]):

冒泡排序

简单代码实现

先简单实现以下,很简单,两层循环,相邻元素比较:

public void sort(int[] nums) { for (int i = 0; i < nums.length; i++) { for (int j = i + 1; j < nums.length; j++) { //升序 if (nums[i] > nums[j]) { //交换 int temp = nums[i]; nums[j] = nums[i]; nums[i] = temp; } } } } 冒泡排序优化

上面的代码实现还存在一个问题,什么问题呢?

哪怕数组有序,它还是会接着遍历。

所以可以用一个标志位来标志数组是否有序,假如有序,就跳出遍历。

public void sort(int[] nums) { //标志位 boolean flag = true; for (int i = 0; i < nums.length; i++) { for (int j = 0; j < nums.length - i - 1; j++) { //升序 if (nums[j] > nums[j + 1]) { //交换 int temp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = temp; } } //如果是有序的,结束循环 if (flag) { break; } } } 冒泡排序性能分析

大小相同的元素没有交换位置,所以冒泡排序是稳定的。

算法名称 最好时间复杂度 最坏时间复杂度 平均时间复杂度 空间复杂度 是否稳定
冒泡排序   O(n)   O(n²)   O(n²)   O(1)   稳定  
选择排序 选择排序原理

选择排序为什么叫选择排序?原理是怎么样的呢?

它的思路:首先在未排序的序列中找到最小或者最大的元素,放到排序序列的起始位置,然后再从未排序的序列中继继续寻找最小或者最大元素,然后放到已经排序序列的末尾。以此类推,直到所有元素排序完毕。

动图如下(来源参考[4]):

选择排序

来看一个例子,用选择排序的方式排序数组 [2,5,4,1,3]。

第一趟,找到数组中最小的元素1,将它和数组的第一个元素交换位置。

选择排序1

第二趟,在未排序的元素中找到最小的元素2,和数组的第二个元素交换位置。

选择排序2

第三趟,在未排序的元素中找到最小的元素3,和数组的第三个元素交换位置。

选择排序-3

第四趟,在未排序的元素中找到最小的元素4,和数组的第四个元素交换位置。

选择排序4

那么到这,我们的数组就是有序的了。

选择排序5

选择排序代码实现

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwjggf.html