一、冒泡排序简介
冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
二、算法思想
给定一个无序数列,从最左侧开始,两个指针位置比较,逆序则调换,正序不动,继续后移两个指针,直到末尾,此为一趟,重复上述步骤,排序整个数列。
一趟:
第一次比较 0 1 位置,逆序调换,正序不动
第二次比较 1 2 位置,逆序调换,正序不动
第三次比较 2 3 位置,逆序调换,正序不动
...
三、代码实现
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]) {
SortUtil.swap(arr, j, j + 1);
}
}
}
四、数字换位的三种方法
不论是冒泡排序还是其他排序方式,都涉及到数字之间的换位。
像通过创建中间值的方式来解决换位问题是最常见也是最简单的实现方法。另外还有两个换位的方式,我来简单说明一下。
4.1 加减换位法
这种方法简单来说就是利用两数之和,先加再减。
/* 1、加减换位法*/
int a = 10;
int b = 8;
System.out.println("a = " + a + ", b = " + b);
a = a + b; // 18
b = a - b; // 10
a = a - b; // 8
System.out.println("a = " + a + ", b = " + b);
输出结果:
4.2 异或换位法
这种方法利用异或(^)运算,在二进制层面寻求问题的解答方案。
/* 2、异或换位法*/
int x = 10;
int y = 8;
System.out.println("x = " + x + ", y = " + y);
x = x ^ y;
y = x ^ y;
x = x ^ y;
System.out.println("x = " + x + ", y = " + y);
输出结果:
注意:当使用异或运算进行数组位置调换时,一定不可以指定同一个位置,这样会导致这个位置上内存中的元素被刷成 0 。
public static void main(String[] args) {
int[] arr = {3, 2, 1, 4};
SortUtil.printArr(arr);
int idx = 1;
arr[idx] = arr[idx] ^ arr[idx];
arr[idx] = arr[idx] ^ arr[idx];
arr[idx] = arr[idx] ^ arr[idx];
SortUtil.printArr(arr);
}
3 2 1 4
3 0 1 4
4.3 异或运算
从上面两种不需要中间值的换位法来看,很明显前者“加减换位法”理解起来要简单一些。而第二种“异或换位法”由于采用了二进制层面的运算规则,所以,如果以十进制的角度去寻找它得以解决问题的原因就不那么轻松。所以接下来我们来聊一聊异或运算的规则以及我的一些理解。
异或的规则是:
相异为 1 ,相同为 0
以上面的例子为例。
x = 10 = 1010B
y = 8 = 1000B
根据异或的规则,将两个数按位异或的话,将步骤拆分,可以看到两个数变化的过程:
① x = x ^ y = 1010 ^ 1000 = 0010
② y = x ^ y = 0010 ^ 1000 = 1010 = 10
③ x = x ^ y = 0010 ^ 1010 = 1000 = 8
是不是很神奇?我们在惊叹“异或运算”的强大时,是否应该再来重新审视一下“异或”的概念?
究竟什么是“异或”?从中文的字面上来理解,“异”代表不同、相异;而“或”表示或者、可能,在“异或”的语境下表示前面“异”的另一种可能,即相同。
而实际上,人为规定的 “相异为 1 ,相同为 0” 并不是绝对的,只是一种符合 1 、0 (对、错)概念或习惯的一种标记方式。换句话说,如果我们规定 “相异为0, 相同为 1” ,那么上面的结果依然相同。
// 规定:相异为0, 相同为 1
x = x ^ y = 1010 ^ 1000 = 1101
y = x ^ y = 1101 ^ 1000 = 1010 = 10
x = x ^ y = 1101 ^ 1010 = 1000 = 8
看来,的确如此。
所以,①中两个数按位异或之后,得到的值(0010)并不代表数字(即如果将异或的结果转化为十进制不具有任何意义),而是携带了一个信息,这个信息记录的是这两个数各个位的异同。
这样,②和③的逻辑就不难解释了,数字的每个位遇到1就会变成另一个数(0 变 1,1 变 0);而遇到0则保持不变。就好像在做“找不同”的游戏,先找出不同的位置,然后进行转换。
综上就是关于冒泡排序算法的一些个人见解和实现思路。希望大家文末踊跃留言。