排序
排序算法有很多,其中最常用的有冒泡排序、插入排序、选择排序、归并排序、快速排序、计数排序、基数排序、桶排序。
算法的内存消耗可以通过空间复杂度来衡量,原地排序算法特指空间复杂度O(1)的排序算法,排序算法的稳定性是指待排序的序列中存在值相等的元素,经过排序之后,相等元素的先后顺序不变。
冒泡排序(Bubble Sort)
冒泡排序只会操作相邻两个元素的数据,每次冒泡操作都会比较相邻元素大小,如果不满足条件则互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,就完成了 n 个数据的排序工作。
// 冒泡排序,a表示数组,n表示数组大小
public void bubbleSort(int[] a, int n) {
if (n <= 1) return;
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; // 没有数据交换,提前退出
}
}
冒泡排序只涉及相邻元素的交换,只需要常量级的临时空间,时间复杂度O(1),是原地排序算法。在冒泡排序中,只有交换才可以改变两个元素的前后顺序。为了保证冒泡排序算法的稳定性,当有相邻的两个元素大小相等的时候,我们不做交换,相同大小的数据在排序前后不会改变顺序,所以冒泡排序是稳定的排序算法。最好时间复杂度是数据有序时,只需要进行一次冒泡操作就可以结束了,最好时间复杂度为O(n)。最坏时间复杂度是要排序的元素是倒序,要进行n次冒泡,最坏时间复杂度为O(n^2)。
如果用概率论方法定量分析平均时间复杂度,涉及的数学推理和计算就会很复杂。可以通过有序度和逆序度来分析。有序度是数组中具有有序关系的元素对的个数。比如2,4,5有序对为(2,4),(2,5),(4,5),有序度为3。对于一个倒序排列的数组,比如 6,5,4,3,2,1