冒泡排序
跳到导航
跳到搜索
https://www.bilibili.com/video/BV1tW4y1i7Mo
算法描述
- 首先从未排序数组的首位开始,和后面相邻的数字进行比较,如果前面一个比后面一个大,那么则进行交换。
- 接下来再将第二个位置的数字和后面相邻的数字进行比较,如果大,那么则进行交换,直到将最大的数字交换到数组的尾部
- 然后再从排序的数组的首位开始,重复前面两步,将最大的数组交换到未排序数组的尾部(交换到尾部的数字是已经排好序的)。
- 如此反复,直到排序完毕。
比如:
排序前的原始数组
8 | 6 | 12 | 7 | 2 | 5 | 4 | 1 | 9 |
---|
第1个元素和第2个元素比较,如果第1个元素比第2个元素大的话,它们就会交换位置,这里8>6,所以交换位置,变成:
6 | 8 | 12 | 7 | 2 | 5 | 4 | 1 | 9 |
---|
接下来,再以第2个元素和第3个元素进行比较,8<12,不变;
接下来,再使用第3个元素和第4个元素进行比较,12>7,进行交换:
6 | 8 | 7 | 12 | 2 | 5 | 4 | 1 | 9 |
---|
……,就这样一直进行比较交换,把值最大的元素一直往后面移,直到值最大的元素被交换到数组的尾部:
6 | 8 | 7 | 2 | 5 | 4 | 1 | 9 | 12 |
---|
算法实现
分解1:将第一个数字和后面相邻的数字进行比较,如果大则进行交换
public class Test {
public static void main(String[] args) {
int[] arr = {8,6,12,7,2,5,4,1,9};
//比较两个元素
if (arr[0] > arr[1]) {
int tmp = arr[0];
arr[0] = arr[1];
arr[1] = tmp;
}
if (arr[1] > arr[2]) {
int tmp = arr[1];
arr[1] = arr[2];
arr[2] = tmp;
}
if (arr[2] > arr[3]) {
int tmp = arr[2];
arr[2] = arr[3];
arr[3] = tmp;
}
//……
}
}
分解2:用循环实现比较、交换的过程
public class Test {
public static void main(String[] args) {
int[] arr = {8, 6, 12, 7, 2, 5, 4, 1, 9};
for (int i = 0; i < arr.length; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
}
}
会发现抛出异常:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 9
at bubblesort.Test.main(Test.java:10)
这是因为当 i 为 arr.length-1 时,arr[i+1] 发生了数组下标越界,而且实际上,对于 n 个元素的数组,我们也只需要进行 n - 1 次的比较大小的判断,
比如本例中有9个元素,每两个位置之间进行比较,就需要进行8次比较(像五根手指四个缝O(∩_∩)O哈哈~),arr.length-1就是8,“i=0;i<8;i++”,就将循环i值为“0,1,2,3,4,5,6,7”8个值。
于是修正成:
public class Test {
public static void main(String[] args) {
int[] arr = {8, 6, 12, 7, 2, 5, 4, 1, 9};
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}// end for
}//end main
}
到这里,我们完成了第一轮的冒泡,整个数组可以看成两部分,左边是未排序的,右表是已排序的(数组中的最大值),
分解3:多轮冒泡
public class Test {
public static void main(String[] args) {
int[] arr = {8, 6, 12, 7, 2, 5, 4, 1, 9};
//第一轮,最大值到最后
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
//第二轮,次大的值到倒数第2个位置
for (int i = 0; i < arr.length - 2; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
//第三轮
for (int i = 0; i < arr.length - 3; i++) {
if (arr[i] > arr[i + 1]) {
int tmp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = tmp;
}
}
//……
}
}
双层循环代替:
完整实现
public class BubbleSort {
public static void bubbleSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int e = arr.length - 1; e > 0; e--) {// 0 ~ e
boolean swapped = false;
for (int i = 0; i < e; i++) {
if (arr[i] > arr[i + 1]) {
swap(arr, i, i + 1);
swapped = true;
}
}//end for
if (!swapped) {
break;
}
}//end for
}//end bubbleSort
/**
* 交换 arr 的 i 和 j 位置上的值
* 相较于:
* int tmp = arr[i];
* arr[i] = arr[j];
* arr[j] = tmp;
* 的写法,节省了一个额外的空间
* @param arr
* @param i
* @param j
*/
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];
}
public static void main(String[] args) {
int[] arr = new int[]{6, 8, 4, 3, 9, 7};
SelectionSort.selectionSort(arr);
System.out.print(arr[0]);
for(int i = 1; i < arr.length; i++){
System.out.print(", " + arr[i]);
}
}
}
public class Test {
public static void main(String[] args) {
int[] arr = {8, 6, 12, 7, 2, 5, 4, 1, 9};
for(int i = 1; i < arr.length;i++){
boolean swapped = false;
for (int j = 0; j < arr.length - i; j++){
if (arr[i] > arr[i+1]) {
arr[i] = arr[i] ^ arr[i+1];
arr[i+1] = arr[i] ^ arr[i+1];
arr[i] = arr[i] ^ arr[i+1];
swapped = true;
}
}//end for
if (!swapped) {
break;
}
}//end for
}
}