一、交换排序
交换排序:通过比较序列中任意位置的两个元素,根据比较结果来进行交换,以此达到排序的目的
二、冒泡排序
/**
* 冒泡排序:
* 冒泡排序是一种简单的交换排序算法,以升序为例
* 1.从第一个数开始,比较相邻的两个元素,如果第一个比第二个大,那么两个元素交换位置
* 2.轮到下一轮继续相邻两个元素之间比较并且交换,直到没有可以交换的元素
* 3.除了每一轮排序所得到的最后一个元素,对剩余元素继续比较,直到没有可以比较的元素
*/
public static void bubble1(Integer[] arr) {
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length;
if (n == 1) {
return;
}
int temp;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
三、优化(1)
/**
* 优化1:
* 假如待排序数组是 2、1、3、4、5 这样的情况,按照上面的代码实现,
* 第一轮循环结束后就得到了最终结果。但循环不会停止,而是继续执行,直到结束为止。
* 为了解决这个问题,我们可以设置一个标志位,用来判断当前循环有没有进行交换,
* 如果没有交换那就说明已经完成了排序,直接返回就好。
*/
public static int bubble2(Integer[] arr) {
int count = 0;
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length;
if (n == 1) {
return count;
}
int temp;
for (int i = 0; i < n - 1; i++) {
int flag = 0;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 1; //交换时进行标记
count++; //记录循环次数
}
}
if (flag == 0) { //没有进行交换,说明已经完成排序
return count;
}
}
return count;
}
四、优化(2)
/**
* 优化2:
* 比如3、4、2、1、6、7、8 这个数组,第一次循环后,变为 3、2、1、4、6、7、8 的顺序,
* 我们发现,1 之后的 4 、6、7、8 已经有序了,第二次循环就没必要对后面这段再遍历比较。
* 那么我们需要找到这么一个分界点,其实也不难找,可以想象,由于i之前的元素是无序的,
* 所以一定有交换发生,而i之后的元素是有序的,不会有交换发生,最后发生交换的地点,
* 就是我们要找的分界点。
*/
public static int bubble3(Integer[] arr) {
int count = 0;
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length - 1;
if (n == 1) {
return count;
}
int temp;
for (int i = 0; i < n; i++) {
int lastChange = 0; //最后一次改变的位置
for (int j = 0; j < n; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
lastChange = j; //实时更新最后一次交换的位置
count++;
}
}
if (lastChange == 0) { //没有进行交换,说明已经完成排序
return count;
}
n = lastChange; //把最后一次交换的位置作为下一次循环的终点
}
return count;
}
五、全部代码
public class _1_BubbleSort {
public static void main(String[] args) {
//基础冒泡排序
Integer[] arr1 = {3, 5, 1, 7, 2, 3, 4, 8};
bubble1(arr1);
System.out.println(Arrays.toString(arr1));
//优化1:中途根据标志位判断排序是否完成
Integer[] arr2 = {2, 1, 3, 4, 5};
System.out.println("循环的次数 = " + bubble2(arr2));
System.out.println(Arrays.toString(arr2));
//优化2:根据一次循环中最后一次交换的位置来减少无意义的遍历
Integer[] arr3 = {3, 5, 1, 7, 2, 3, 4, 8};
System.out.println("循环的次数 = " + bubble3(arr3));
System.out.println(Arrays.toString(arr3));
}
/**
* 冒泡排序:
* 冒泡排序是一种简单的交换排序算法,以升序为例
* 1.从第一个数开始,比较相邻的两个元素,如果第一个比第二个大,那么两个元素交换位置
* 2.轮到下一轮继续相邻两个元素之间比较并且交换,直到没有可以交换的元素
* 3.除了每一轮排序所得到的最后一个元素,对剩余元素继续比较,直到没有可以比较的元素
*/
public static void bubble1(Integer[] arr) {
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length;
if (n == 1) {
return;
}
int temp;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
/**
* 优化1:
* 假如待排序数组是 2、1、3、4、5 这样的情况,按照上面的代码实现,
* 第一轮循环结束后就得到了最终结果。但循环不会停止,而是继续执行,直到结束为止。
* 为了解决这个问题,我们可以设置一个标志位,用来判断当前循环有没有进行交换,
* 如果没有交换那就说明已经完成了排序,直接返回就好。
*/
public static int bubble2(Integer[] arr) {
int count = 0;
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length;
if (n == 1) {
return count;
}
int temp;
for (int i = 0; i < n - 1; i++) {
int flag = 0;
for (int j = 0; j < n - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = 1; //交换时进行标记
count++; //记录循环次数
}
}
if (flag == 0) { //没有进行交换,说明已经完成排序
return count;
}
}
return count;
}
/**
* 优化2:
* 比如3、4、2、1、6、7、8 这个数组,第一次循环后,变为 3、2、1、4、6、7、8 的顺序,
* 我们发现,1 之后的 4 、6、7、8 已经有序了,第二次循环就没必要对后面这段再遍历比较。
* 那么我们需要找到这么一个分界点,其实也不难找,可以想象,由于i之前的元素是无序的,
* 所以一定有交换发生,而i之后的元素是有序的,不会有交换发生,最后发生交换的地点,
* 就是我们要找的分界点。
*/
public static int bubble3(Integer[] arr) {
int count = 0;
if (arr == null) {
throw new NullPointerException();
}
int n = arr.length - 1;
if (n == 1) {
return count;
}
int temp;
for (int i = 0; i < n; i++) {
int lastChange = 0; //最后一次改变的位置
for (int j = 0; j < n; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
lastChange = j; //实时更新最后一次交换的位置
count++;
}
}
if (lastChange == 0) { //没有进行交换,说明已经完成排序
return count;
}
n = lastChange; //把最后一次交换的位置作为下一次循环的终点
}
return count;
}
}