我们知道一般的冒泡排序是指:
1、将一个数与它后面的那一个数进行比较,如果前面>后面,则两者交换位置。
2、对数组中的每一个数都进行这样的操作,一个循环下来最大的数值就会到达数组的最后面。
3、再将数组范围缩小一个(即再次比较时不看数组最后且最大的那个),再次循环上面的步骤。
(因为1,2,3,6,1在12循环后是1,2,3,1,6 如果不继续进行循环,则答案错误)
当数组的范围缩小到只剩下一个数的时候,那么数组就已经有序了,冒泡排序结束。
代码一:冒泡排序原始解决方案
public static void sortFunc1(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
for (int i = arr.length - 1; i > 0; i--) { //第一循环:在将数组最大的值放在最后的时候,逐渐缩小范围
for (int j = 0; j < arr.length - 1; j++) { //第二循环:判断当前数组范围中的每一个数的顺序是否正确
if (arr[j] > arr[j + 1]) {
swap(arr, j + 1, j);
}
}
}
}
虽然说到这儿冒泡排序就已经完成了,但是实际上这个算法还有很多可以优化的空间,简单举两个例子来说:
一、如果在某个循环中,数组已经排好序了,但是数组范围并没有缩小到1
首先应该明确什么时候数组是以及排好序了的:发现数组中所有的数值两两之间并不交换,就可以判断数组已经排好序了,或者数组大小缩减为1。
然后,这种情况如果出现,如果按照最初始的办法是还要继续进行第一循环判断的,这无疑是极大的时间浪费。
这时候我们可以设置一个判断符,判断在第二循环中是否存在这种排好序且数组范围没有缩小到1的情况出现。
代码二:优化代码
public static void sortFunc2(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
boolean flage = true;
while (flage) {
flage = false;
for (int i = arr.length - 1; i > 0; i--) {
for (int j = 0; j < arr.length - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j + 1, j);
flage = true;
}
}
}
}
}
整体思路就是添加一个flage判断符,每次循环都设置为false,如果一个循环中出现两个数之间交换的情况,那么就置为true,否则代表上一个循环中没有任何交换产生,数组已经排好序了,标志符置为false,结束循环
二、如果某个数组中前200是无序的,后10000是有序的,且都大于前200个数
虽然上一个算法以及在初始的基础上进行了优化,但是在遇到这种情况的时候依旧不能够很好的处理,因为我们只是判断了数组在第二循环中是否已经排好了序,并没有判断数组从哪一位开始是有序的。
所以这种情况我们应该解决的问题是:如何判断数组从某一位开始是有序的。
解决这个问题的方法和前一种方法其实是相差不多的,在循环之中,如果数组中的数值两两交换,则代表当下这两个数以前是无序的(如果要更精确一点的话,应该是这两个数的前一个数到数组第一个数可能无序,(比如1,2,3,6,1,8, 9,10在12循环后是1,2,3,1,6,8,9,10)),所以只需要在每次交换数值的时候记录下当前的位置,在进行下一次第一循环的时候从记录的位置开始。
代码三:进一步优化代码
public static void sortFunc3(int[] arr) {
if (arr == null || arr.length == 0) {
return;
}
int flage = arr.length - 1;
while(flage > 0) {
int end = flage;
flage = 0;
for (int j = 0; j < end; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr, j + 1, j);
flage = j; //记录所交换的两个数的前一个
}
}
}
}
附加swap()
public static void swap(int[] arr, int i, int j) {
arr[i] = arr[i]^arr[j];
arr[j] = arr[i]^arr[j];
arr[i] = arr[i]^arr[j];
}