排序算法
1. 介绍
排序也叫排序算法(Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程。
2. 排序的分类:
- 内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。
- 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。
3. 常见的排序算法分类
4. 算法的时间复杂度
度量一个程序执行时间的两种方法
- 事后统计的方法
这种方法可行,但是有两个问题:一是要想对设计的算法的运行性能进行评测,需要实际运行该程序;二是所得时间的统计量依赖于计算机的硬件、软件等环境因素,这种方式,要在同一台计算机的相同状态下运行,才能比较哪个算法速度更快。- 事先估算的方法
通过分析某个算法的时间复杂度来判断哪个算法更优。
4.1 时间频度
基本介绍:一个算法花费的时间与算法种语句的执行次数成正比,哪个算法种语句执行次数多,它花费时间就多。一个算法种的语句执行次数称为语句频度或时间频度。记为 T(n)。
4.2 时间复杂度
- 一般情况下,算法种的基本操作语句的重复执行次数是问题规模n 的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n) 的极限值为不等于0的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。
- T(n)不同,但时间复杂度可能相同。如T(n)=n2 + 7n + 6 与 T(n)=3n2 + 2n + 2 它们的T(n)不同,但时间复杂度相同,都为O(n2)。
3. 计算时间复杂度的方法:
- 用常数1代替运行时间中的所有加法常数
- 修改后的运行次数函数中,只保留最高阶项
- 去除最高阶项的系数
4.3 平均时间复杂度和最坏时间复杂度
- 平均时间复杂度是指所有可能的输入实例均以等概率出现的情况下,该算法的运行时间。
- 最坏情况下的时间复杂度称最坏时间复杂度。一般讨论的时间复杂度均是最坏情况下的时间复杂度,这样做的原因是:最坏情况下的时间复杂度是算法在任何输入实例上运行时间的界限,这就保证了算法的运行时间不会比最坏情况更长。
- 平均时间复杂度和最坏时间复杂度是否一致,和算法有关
4.4 常见的时间复杂度
4.5 常数阶O(1)
4.6 对数阶 (举例:O(log2n))
4.7 线性阶 O(n)
4.8 线性对数阶 O(nlogN)
4.9 平方阶 O(n2)
5. 算法的空间复杂度
- 类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)定义为该算法所耗费的存储空间,他也是问题规模n的函数。
- 空间复杂度是对一个算法在运行过程种临时占用存储空间大小的度量。有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元,例如快速排序和归并排序算法就属于这种情况。
3.在做算法分析时,主要讨论的是时间复杂度。从用户使用体验上看,更看重的程序执行的速度。一些缓存产品和算法(基数排序)本质就是用空间换时间。
6.冒泡排序
冒泡排序(Bubble Sorting)的基本思想是:通过对待排序序列从前往后(从下标较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样逐渐向上冒。
因为排序的过程中,各元素不断解决自己的位置,如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换。从而减少不必要的比较。
7.选择排序
7.1 选择排序思路分析
选择排序(select sorting) 也是一种简单的排序方法。它的基本思想是:
第一次从arr[0] ~ arr[n-1]中选取最小 值,与arr[0]交换,第二次从arr[1] ~ arr[n -1]中选取最小值,与arr[1]交换,第三次从arr[2] ~ arr[n-1]中选取最小值,与arr[2]交换,。。。,第i次从arr[i - 1] ~ arr[n - 1]中选取最小值,与arr[i -1]交换,。。。,第 n - 1次从arr[n - 2] ~ arr[n - 1]中选取最小值,与arr[n - 2]交换,总共通过n - 1次,得到一个按排序码从小到大排序的有序序列。
7.2 选择排序代码实现
原始数组:101,34,119,1
第一轮排序:1,34,119,101
第二轮排序:1,34,119,101
第三轮排序:1,34,101,119
说明:
- 选择排序一共有 ** ** 轮排序
- 每 1 轮排序,又是一个循环,循环的规则(代码)
2.1 先假定当前这个数是最小数
2.2 然后和后面的每个数进行比较,如果发现有比当前数更小的数,就重新确定最小数,并得到下标
2.3 当遍历到数组的最后时,就得到本轮最小数和下标
2.4 交换(代码)
public class SelectSort {
public static void main(String[] args) {
int[] arr = {
345,1,34,119,101};
SelectSort(arr);
}
// 选择排序
public static void SelectSort(int[] arr) {
// 在推导过程中,我们发现了规律,因此,可以使用for来解决
// 选择排序时间复杂度是O(n2)
for (int i = 0; i < arr.length - 1; i++) {
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
//说明假定的最小值,并不是最小
min = arr[j];//重置min
minIndex = j;//重置minIndex
}
}
// 将最小值,放在arr[0],即交换
if (minIndex != i) {
arr[minIndex] = arr[i];
arr[i] = min;
}
System.out.println(Arrays.toString(arr));
}
}
}
8. 直接插入排序
8.1 介绍
插入式排序属于内部排序法,是对于欲排序的元素以插入的方式寻找该元素的适当位置,以达到排序的目的。
插入排序(Insertion Sorting)的基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表只包含一个元素,无序表中包含有n - 1 个元素,排序过程中每次从无序表中取出一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
8.2 直接插入排序代码实现
public class InsertionSort {
public static void main (String[] args) {
int[] arr = {
101,34,119,1,-1,89};
insertionSort(arr);
}
// 插入排序