通常使用的排序算法以冒泡为主,但是在实际的应用过程中,选择排序的效果是远远好于冒泡的。
但是两者的时间复杂度其实是没有区别的,都是O(n^2),那么其原因在于哪里呢?以如下主程序进行演示
public class Test1 {
static int[] list = new int[80000];
static {
for (int i = 0; i < list.length; i++) {
list[i] = (int) (Math.random() * 8000000);
}
}
public static void main(String[] args) {
long l = System.currentTimeMillis();
//除了最后一个元素,比较相邻两个元素,如果大于则交换位置,
buboSort1(list);
//遍历n-1次,每次把最小值塞在最前面
//selectSort2(list);
long s = System.currentTimeMillis();
System.out.println(Arrays.toString(list));
System.out.println((s - l) / 1000);
}
}
首先,我们来看冒泡排序来看,其实现方法为buboSort1:
public static void buboSort1(int[] aar) {
for (int i = 0; i < aar.length; i++) {
//每一次交互都会减少交换次数
for (int j = 0; j < aar.length - i - 1; j++) {
if (aar[j] > aar[j + 1]) {
int temp = aar[j + 1];
aar[j + 1] = aar[j];
aar[j] = temp;
}
}
}
}
可以看到8w条数据,执行所需的时间为13s:
而如果使用选择排序,则会大大降低其运行时间:
private static void selectSort2(int[] aar) {
//以list为基准,实现选择排序,虽然和冒泡的时间复杂度相同,但是实际执行效果远远好于冒泡
//原因在于,变量的交换主要在双层for循环以外,防止了和冒泡排序一样的全组遍历交换
for (int i = 0; i < aar.length; i++) {
int min = aar[i];
int minIndex = i;
//此循环未做任何交换,所以速度快,而冒泡恰恰相反,找到最小变量
for (int j = i + 1; j < aar.length - 1 - i; j++) {
if (min > aar[j]) {
min = aar[j];
minIndex = j;
}
}
//交换最小变量和当前循环值的位置
if (minIndex != i) {
aar[minIndex] = aar[i];
aar[i] = min;
}
}
}
通过运行程序,可以看到其耗时仅为1s:
那么其原因在于哪里呢?
原来在选择排序中,变量的交换主要在双层for循环以外,防止了和冒泡排序一样的全组遍历交换。
在双层for循环以内,未作任何数组交换,仅仅是对最小变量和索引进行赋值,这样便大大加快了运行速率。
在普通的冒泡排序中,甚至是很容易写错的选择排序中,为了节省代码行数,所有的交换都在双层for循环以内完成,因为最小或者最大值的获取不可能经过一次查找便结束,那么数组内数据的交换也必定不止一次。
在这种情况下,大大拖慢了cpu的运行速率。
错误的选择排序如下:
private static void selectSort(int[] aar) {
for (int i = 0; i < aar.length - 1; i++) {
for (int j = i + 1; j < aar.length; j++) {
if (aar[i] > aar[j]) {
int temp = aar[i];
aar[i] = aar[j];
aar[j] = temp;
}
}
}
}
大家看,和冒泡排序是不是基本一模一样?