冒泡排序
写过好多次排序了,我总感觉冒泡是最难的,这次仔细阐述一下冒泡排序的原理。希望能给和我有一样问题的人一些帮助。
一个flash让你明白冒泡排序原理
http://student.zjzk.cn/course_ware/data_structure/web/flashhtml/maopaopaixu.htm
算法介绍
假设数组为a,数组长度为n,不考虑边界条件和数组长度为1的情况。以一次冒泡为例,多次冒泡重复此过程即可。
- index=n-1;
- 如果index-1=0,本次冒泡结束,否则进入3;
- a[index]和a[index-1]的元素比较大小,若a[index-1]>a[index],交换a[index-1]和a[index],index=index-1,返回2。
代码实现
1 | public static void bubbleSort1(int[] a) { |
这是最基本的冒泡排序,如果你仔细换茬,你会发现这个冒泡排序和你经常写的不太一样。
第4行的内层循环中,没有使用i。这也是我在第二行添加了i的作用的原因。
这种情况下的时间复杂度和空间复杂度是这样的:
最好o(n^2),最差o(n^2),平均o(n^2),空间复杂度o(1),稳定。
为了减少内层循环次数,可以将第4行代码进行如下修改:1
for (int j = a.length - 1; j > i; j--) {
此时,i的作用不仅是控制外层循环的次数,也控制了内存循环的次数,外层循环每完成一次,内层循环执行的次数就-1。完整代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public static void bubbleSort2(int[] a) {
/**
* i的作用,
* 1. 循环次数,循环“数组长度-1”次就完成排序了
* 2. 限制内层循环遍历的次数,外层循环每完成一次,内存循环遍历次数-1
*/
for (int i = 0; i < a.length - 1; i++) {
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
int tmp = a[j];
a[j] = a[j - 1];
a[j - 1] = tmp;
}
}
}
}
这种情况下的时间复杂度和空间复杂度是这样的:
最好o(n^2),最差o(n^2),平均o(n^2),空间复杂度o(1),稳定。
然而被人熟知的冒泡排序算法中,时间复杂度最好的是o(n)。实现的代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public static void bubbleSort3(int[] a) {
/**
* i的作用,
* 1. 循环次数,循环“数组长度-1”次就完成排序了
* 2. 限制内层循环遍历的次数,外层循环每完成一次,内存循环遍历次数-1
*/
boolean flag = true;//flag为true,表示已经排序完成。
for (int i = 0; i < a.length - 1; i++) {
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
int tmp = a[j];
a[j] = a[j - 1];
a[j - 1] = tmp;
flag = false;
}
}
if (flag) {
return;
}
}
}
这种情况下的时间复杂度和空间复杂度是这样的:
最好o(n),最差o(n^2),平均o(n^2),空间复杂度o(1),稳定。
总结
冒泡排序除非特定的业务场景,没有人会使用。
之所以存在这种排序算法,更多的是让人理解排序的基本概念。
上面列出的三种排序,我个人觉得都是标准的冒泡排序,也不一定说最好的时间复杂度必须是o(n)才能叫冒泡排序,只是各种实现上性能有所不同。你怎么看?