【数据结构】——八大排序(以Java为例)
https://www.cnblogs.com/yzsn12138/p/16989094.html
主要内容如下
作为高级语言(以下的代码都以Java)为例,如果需要对数组排序,通常都是直接调用排序方法 sort 。例如:
1 int [] sortArray = {1,4,7,5,8,10,2,3,9,6}; 2 // 排序前 3 System.out.println("排序前数组"); 4 for (int i: sortArray) { 5 System.out.print(i + ","); 6 } 7 System.out.println(); 8 Arrays.sort(sortArray); 9 System.out.println("排序后数组:"); 10 for (int i: sortArray) { 11 System.out.print(i + ","); 12 } 13 System.out.println();
所以,似乎实际不需要知道排序的原理也不影响工作。
不过,它是数据结构的基础。知其然,并且知其所以然,才能不蒙昧。所以,今天,我们来复习常见的八大排序方法,并对比这几种排序的属性。八大排序方法的分类如下:
基本概念概述
排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
时间复杂度:又称时间复杂性,用于评估执行程序所消耗的时间,可以估算出程序对处理器的使用程度。
空间复杂度:有称空间复杂性,用于评估执行程序所占用的内存空间,可以估算出程序对处理器的使用程度。
排序的稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,在排序后的序列中,r[i]仍然在r[j]之前,则称这种排序算法是稳定的,否则称为不稳定。为了方面理解,示意图如下。
开门直接抛出主题,各种排序的综合比较如下:
排序方法 | 平均情况 | 最好情况 | 最坏情况 | 辅助空间 | 稳定性 |
直接插入排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
希尔排序 | O(nlogn~n^2) | O(n^1.3) | O(n^2) | O(1) | 不稳定 |
直接选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 |
冒泡排序 | O(n^2) | O(n) | O(n^2) | O(1) | 稳定 |
快速排序 | O(nlogn) | O(nlogn) | O(n^2) | O(1) | 不稳定 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 |
计数排序 | O(N) | O(N) | O(N) | O(N) | 不稳定 |
直接插入排序
基本思想
把待排序的数逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列。
✍️一般地,我们把第一个看作是有序的,所以我们可以从第二个数开始往前插入,使得前两个数是有序的,然后将第三个数插入直到最后一个数插入。
思路图示
口头描述有些太抽象了。我们不妨用图表示排序的方法(这里以数组:1,4,7,5,8,10,2,3,9,6)为例。
注:从小到大排列,则从数列的右边到左边依次替换;如果从大到小排列,则从数列的左边到右边依次替换。
实现代码
1 public void insertSort(int[] arrs ){ 2 int n = arrs.length; 3 int temp ; // 定义一个变量,将要插入的数保存起来 4 for(int i = 0 ; i < n -1 ; i ++){ 5 temp = arrs[i + 1]; 6 for (int j = i ; j >= 0 ; j --){ 7 if(temp >= arrs[j]){ 8 break; 9 }else{ 10 arrs[j+ 1] = arrs [j]; 11 arrs[j] = temp; 12 } 13 } 14 } 15 }
直接排序分析
- 时间复杂度:第一趟end最多往前移动1次,第二趟是2次……第n-1趟是n-1次,所以总次数是1+2+3+……+n-1=n*(n-1)/2,所以说时间复杂度是O(n^2)
最好的情况: 顺序
最坏的情况: 逆序
外层的循环次数,复杂度是O(logN)
每一组的数的个数大概是N/gap,总共有N/n/gap个组,所以调整的次数应该是(1+2+......+N/gap-1)*gap,所以我们分成两种极端来看待这个问题:
当gap很大,也就是gap = N/2的时候,调整的次数是N/2,也就是O(N)
当gap很小,也就是gap = 1的时候,按道理来讲调整的次数应该(1+2+......+N-1)*gap,应该是O(n^2),但是这时候应该已经接近有序,次数没有那么多,所以我们不如就看作时间复杂度为O(N)
综上:希尔排序的时间复杂度应该是接近O(N*logN)
- 空间复杂度:由于没有额外开辟空间,所以空间复杂度为O(1)。
- 稳定性:稳定。
希尔排序
基本思路
希尔排序是建立在直接插入排序之上的一种排序,希尔排序的思想上是把较大的数尽快的移动到后面,把较小的数尽快的移动到后面。先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。(直接插入排序的步长为1),这里的步长不为1,而是大于1,我们把步长这个量称为gap,当gap>1时,都是在进行预排序,当gap==1时,进行的是直接插入排序。
思路图示
实现代码
希尔排序分析
- 时间复杂度:第一趟end最多往前移动1次,第二趟是2次……第n-1趟是n-1次,所以总次数是1+2+3+……+n-1=n*(n-1)/2,所以说时间复杂度是O(n^2)
最好的情况: 顺序。
最坏的情况: 逆序。
- 空间复杂度:由于没有额外开辟空间,所以空间复杂度为O(1)。
- 稳定性:不稳定。 我们可以这样想:相同的数被分配到不同的组里,我们就不能保证原有的顺序了。
直接选择排序
堆排序
冒泡排序
快速排序
归并排序