升序排序
核心步骤
-
从头开始比较每一对相邻元素,如果第一个比第二个大,就交换位置。-->经过一轮后最大的元素就到最后了。
-
对于最后一位之前的元素执行重复步骤1,就能对所有元素进行升序排列。
步骤一:
//比较,筛选出当前列最大的数放到最后
for (int start = 1; start < end; start++) {
if (data[start] < data[start - 1]) {
swap(data, start, start - 1);
}
}
步骤二:
//从后面逐步减少遍历个数
for (int end = data.length; end > 1; end--) {
步骤一
}
全部代码:
public class BubbleSort {
public static void main(String[] args) {
int[] array = {10, 2, 6, 1, 7};
sort(array);
for (int i1 : array) {
System.out.println(i1);
}
}
private static void sort(int[] data) {
//从后面逐步减少遍历个数
for (int end = data.length; end > 1; end--) {
//比较,筛选出当前列最大的数放到最后
for (int start = 1; start < end; start++) {
if (data[start] < data[start - 1]) {
swap(data, start, start - 1);
}
}
}
}
private static void swap(int[] data, int first, int end) {
int temp = data[first];
data[first] = data[end];
data[end] = temp;
}
}
优化一
如果拿到的元素就是有序的。可以提前终止排序。
其实每一趟扫描之后,就能确定元素是否有序。如下:
if (data[start] < data[start - 1]) {
swap(data, start, start - 1);
}
如果swap一次都没执行,说明当前元素已经是有序的了。
所以我们可以加一个标识,用来记录当前遍历是否有序,此时就没必要进行下一次的遍历了。
//优化后的sort
private static void sort2(int[] data) {
//从后面逐步减少遍历个数
for (int end = data.length; end > 1; end--) {
boolean sorted = true;
//比较,筛选出当前列最大的数放到最后
for (int start = 1; start < end; start++) {
if (data[start] < data[start - 1]) {
swap(data, start, start - 1);
//序列无序的
sorted = false;
}
}
//当前序列已经是有序的了,没必要再遍历
if (sorted) {
break;
}
}
}
**Note:**只是针对数据是提前有序的有优化效果。如果数据完全无序,那么由于代码行数多了,甚至会导致时间还长了点。
测试代码:
public static void main(String[] args) {
//获取一个升序数组
Integer[] array = Integers.ascOrder( 1, 100000);
Integer[] array1 = Integers.copy(array);
assert array != null;
Times.test("冒泡排序", () -> {
sort(array);
});
Times.test("冒泡排序2", () -> {
sortPro(array1);
});
}
输出:
【冒泡排序】
开始:13:48:10.554
结束:13:48:14.159
耗时:3.605秒
-------------------------------------
【冒泡排序2】
开始:13:48:14.161
结束:13:48:14.165
耗时:0.004秒
-------------------------------------
Process finished with exit code 0
优化二
尾部局部有序
可以记录最后一次交换的位置,最后一次交换位置后续的元素就是有序的。
比如: 3,4,1,5,7,10
其中最后一次是1的位置,他后面的位置就是有序的,没有必要再比较了。
所以下一轮再进来的时候只需要将前面无序的再扫描一遍就行
private static void sort3(Integer[] data) {
//从后面逐步减少遍历个数
for (int end = array.length-1; end > 0; end--) {
//sortIndex最后会复制给end,
//sortIndex需要考虑完全有序的时候,end会就是初始值,
//此时要退出循环,所以可以设置1,0等让下次循环条件不符合。
int sortIndex = 1;
//比较,筛选出当前列最大的数放到最后
for (int start = 1; start <=end; start++) {
if (cmp(start, start - 1) < 0) {
swap(start, start - 1);
//记录最后一次交换的位置
sortIndex = start;
}
}
//缩小下一轮扫描范围
end = sortIndex;
}
}
测试:
public static void main(String[] args) {
//获取一个尾部是有序的
Integer[] array = Integers.tailAscOrder(1, 100000,3000);
Integer[] array1 = Integers.copy(array);
Integer[] array2 = Integers.copy(array);
assert array != null;
Times.test("冒泡排序", () -> {
sort(array);
});
Times.test("冒泡排序2", () -> {
sort2(array1);
});
Times.test("冒泡排序3", () -> {
sort3(array2);
});
}
输出:
【冒泡排序】
开始:14:30:09.318
结束:14:30:18.402
耗时:9.084秒
-------------------------------------
【冒泡排序2】
开始:14:30:18.404
结束:14:30:19.368
耗时:0.964秒
-------------------------------------
【冒泡排序3】
开始:14:30:19.369
结束:14:30:19.387
耗时:0.018秒
-------------------------------------
Process finished with exit code 0
参考:小码哥的恋上数据结构第二期