1.冒泡排序
之前写过一个排序算法(1),其中总结了冒泡排序 .
冒泡排序的思想,是把相邻的元素两两比较,根据大小来交换元素的位置,每经过一轮的扫描,就会确定出一个最大的元素,即是一个元素有序.
原始的冒泡排序是稳定排序(如果一个数组中存在几个相同的元素,排序前后的相同元素的前后顺序不会发生变更,则认为排序是稳定的)。由于该排序算法的每一轮要遍历所有元素,轮转的次数和元素数量相当,所以时间复杂度是O(N^2) 。
代码如下:
/**
* @description 冒泡排序
* @author zhangdi
* @param arr
* @description : 两两比较,大的往后放; 每一次比较完成之后,下一次就少比较一个元素
* 第一次比较有0个元素不比较;第二次有一个元素不需要比较;第三次有两个元素不需要比较;
* 共需要比较arr.length-1次
*/
public static void BubbleSort(int[] arr) {
int temp;// 临时变量
if (arr == null || arr.length == 0)
return;
for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
/**
* @description 冒泡排序-2
* @param arr
* @author zhangdi
*/
public static void BubbleSort2(int[] arr) {
int temp;// 临时变量
if (arr == null || arr.length == 0)
return;
for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
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;
}
}
}
}
2冒泡排序改进
现在我们思考一下,会发现这个算法还有优化的空间,比如说但是一个数组前一半部分已经是有序的,当某轮中没有发生元素交换,就可以确定,整个数组已经是有序的,此时就不需要进行接下来的扫描交换了.
/**
* @description 冒泡排序-1-优化
* @author zhangdi
* @param arr
* * 针对问题:数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到arr.length-1次,后面的比较没有意义的。
* 方案: 设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
* 这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
*
*/
public static void BubbleSort1_better(int[] arr) {
int temp;// 临时变量
boolean flag;
if (arr == null || arr.length == 0)
return;
for (int i = 0; i < arr.length - 1; i++) { // 表示趟数,一共arr.length-1次。
flag = false;
for (int j = arr.length - 1; j > i; j--) {
if (arr[j] < arr[j - 1]) {
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
if (!flag)
break;
}
}
冒泡排序三改进
上面的算法还有优化的空间吗?答案是有,假如存在一个数组,前缀几个元素是无序的,而后面大部分皆是有序的,上面的版本并不能解决这种情况下出现的中间部分的反复的扫描,这些扫描交换的元素集中在数组前部.
多出来的时间消耗是后缀中已经有序的元素的反复的扫描交换,其实是不必要的;–>如何确定最后扫描交换的元素的标志在哪?而不是亦步亦趋的逐步收缩.
由此得出版本三
/**
* @description 冒泡排序-3
* @param arr
* @author zhangdi
*/
private static void BubbleSort1_better(int[] array) {
int tmp = 0;
// 记录最后一次交换的位置
int lastExchangeIndex = 0;
// 无序数列的边界,每次比较只需要比到这里为止
int sortBorder = array.length - 1;
for (int i = 0; i < array.length; i++) {
// 有序标记,每一轮的初始是true
boolean isSorted = true;
for (int j = 0; j < sortBorder; j++) {
if (array[j] > array[j + 1]) {
tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
// 有元素交换,所以不是有序,标记变为false
isSorted = false;
// 把无序数列的边界更新为最后一次交换元素的位置
lastExchangeIndex = j;
}
}
sortBorder = lastExchangeIndex;
if (isSorted) {
break;
}
}
}