文章目录
1. 排序算法要关注哪些问题
1) 复杂度
对于算法,我们首先考虑的就是其时间复杂度和空间复杂度。
(1) 时间复杂度
在上一篇文章中,我们说到,复杂度是估计的趋势,所以我们常常忽略常数项。但是对于排序算法,如果数据规模不大,常数项对执行时间的影响就大了,所以我们还要关注常数项、低阶项和系数。
另外,由于序列顺序不一定,不同情况下的时间复杂度也不同,所以我们还要考虑最好情况和最坏情况。
(2) 空间复杂度
这里引入了一个新的概念,我们把O(1)的空间复杂度的排序算法称为原地排序。
2) 稳定性
我们平时说的稳定性,是指波动程度很小。这里举个例子:
假设我们教务处的管理系统,期末排序学生成绩。首先按照成绩进行排名,之后按照学号大小进行二次排名。如果按照学号大小的排名不会打乱前面按照成绩排名的结果,我们就说这个排序算法是稳定的。
简单点说,如果排序 2,3,6,1,8,6,3这个序列,排序之后第二位的3依然在最后一位的3前面,我们就说这个排序是稳定的。
2. 冒泡排序
public void bubbleSort(int[] a) {
int n = a.length;
if (n <= 1) {
return ;
}
// 这里面,i的作用是标记已经排序好的元素数量
// 每次排序,j从0到n-1-i的位置里面找到最大的元素,放到n-1-i的位置
// 整个过程就像冒泡一样,每次将剩余元素中最大的选出来,浮到最后
for (int i = 0; i < n; i++) {
// 提前退出标志
boolean flag = false;
for (int j = 0; j < n - i - 1; j++) {
if (a[j] > a[j + 1]) {
int tmp = a[j];
a[j] = a[j + 1];
a[j + 1] = tmp;
// 表示有数据交换
flag = true;
}
}
// 如果其中一次过程没有元素交换,则说明整个数组已经是有序的了,这时就可以退出了
if (!flag) {
break;
}
}
}
1) 时间复杂度
最好情况下,数据本来就是有序的,所以执行一次就退出了,时间复杂度为O(n)
最差情况下,数据要进行n次冒泡,时间复杂度为O(n^2)
2) 冒泡排序是原地算法
没有使用额外的空间,空间复杂度为O(1)
3) 冒泡排序是稳定算法
当两个元素相等的时候,我们不会交换他们的顺序,所以冒泡排序是稳定的
3. 插入排序
public void insertionSort(int[] a) {
int n = a.length;
if (n <= 1) {
return ;
}
// i从1到n-1遍历每一个元素,插入到前面有序的集合中
for (int i = 1; i < n; i++) {
int value = a[i];
int j = i - 1;
// 找到第i个元素的正确位置,并将大于第i个元素的元素都向后移动一个位置
for (; j >= 0; j--) {
if (a[j] > value) {
a[j + 1] = a[j];
} else {
break;
}
}
// 插入数据
a[j + 1] = value;
}
}
1) 时间复杂度
最好情况,序列是有序的,只需要当前元素和他前一个元素进行一次比较操作,时间复杂度为O(n)
最差的情况,序列是倒序的,每一次都要插入到第一个位置,执行i-1次移动操作,时间复杂度为O(n^2)
2) 插入排序是原地算法
没有使用额外的空间,空间复杂度为O(1)
3) 插入排序是稳定算法
插入的时候,相等的情况,我们将后面的元素插入到前面的元素的后面,不影响之前的排序,所以插入排序是稳定的算法。
4. 选择排序
public void selectSort(int[] a) {
int n = a.length;
if (n <= 1) {
return ;
}
for (int i = 0; i < n - 1; i++) {
// 找到未排序的区域中最小的元素
int j = i;
int minIdx = j;
for (; j < n; j++) {
if (a[j] < a[minIdx]) {
minIdx = j;
}
}
// 将其放置到排序区最后一个 (交换到未排序区第一个)
if (minIdx != i) {
int tmp = a[minIdx];
a[minIdx] = a[i];
a[i] = tmp;
}
}
}
1) 时间复杂度
最好和最坏情况,每次都要查找未排序区域中最小的元素,时间复杂度都为O(n^2)
2) 插入排序是原地算法
没有使用额外的空间,空间复杂度为O(1)
3) 插入排序不是稳定算法
插入算法每一次都要找未排序区域的最小值和前面元素交换位置,这样破坏了稳定性。假设序列6,9,6,1,7,最小的1和第一个6交换,就破坏了两个6的先后顺序,所以插入排序不是稳定算法。
5. 总结
这三种排序算法,可以说大学都会学过,算是开拓思维类的算法,由于时间复杂度高,在实际开发中用的并不多。
下一篇:[排序算法]归并排序、快速排序