基本思想
冒泡排序的基本思想是对比相邻的元素值,如果满足条件就交换元素值,把较小的元素移动到数组前面,把大的元素移动到数组后面(交换两个元素的位置)。
算法分析
冒泡算法由双层循环实现。其外层循环用于控制排序轮数,即(i=arr.length)。而内层循环主要用于对比数组中每个相邻元素大小,以确定是否交换位置,对比和交换次数随排序轮数而减少,及(j=arr.length-1-i)。
时间复杂度
因此冒泡排序总的平均时间复杂度为:
代码示例:
/**
* 通过第三个临时变量方式,普通排序
* @param arr
*/
public static void sort(int[] arr) {
int temp = 0;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 两个数原地交换,不借助于第三个变量,实现两数交换
* @param arr
* @return
*/
public static void subtractSort(int[] arr) {
// 判断数组边界条件
if (arr==null||arr.length<2) return;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
arr[j] += arr[j + 1];
arr[j + 1] = arr[j] - arr[j + 1];
arr[j] -= arr[j + 1];
}
}
}
}
/**
* 按位异或方法,实现两数交换(效率更高推荐*****)
* 算法一定要尽可能高效,因为这是高频操作, 因此采用位运算;
* @param arr
*/
public static void xorSort(int[] arr) {
// 判断数组边界条件
if (arr == null || arr.length < 2) return;
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
arr[j] = arr[j] ^ arr[j + 1];
arr[j + 1] = arr[j] ^ arr[j + 1];
arr[j] = arr[j] ^ arr[j + 1];
}
}
}
}
优化问题
- 针对问题:
数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。
- 方案:
设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
/**
* 优化过后的冒泡排序
* @param arr
*/
public static void fastSort(int[] arr) {
// 判断数组边界条件
if (arr == null || arr.length < 2) return;
boolean flag = false;// 标识变量:记录是否交换
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
flag = true;
arr[j] = arr[j] ^ arr[j + 1];
arr[j + 1] = arr[j] ^ arr[j + 1];
arr[j] = arr[j] ^ arr[j + 1];
}
}
if (!flag) break;
else flag = false;//*****置为false
}
}