您的位置:首页 > 其它

排序算法(一)-冒泡排序

2017-09-16 00:23 183 查看

0. 原理

临近的数字两两比较,按照从小到大或者从大到小的顺序进行交换。

每一趟会将最大或者最小的数字放到最终结果的位置

重复操作直到倒数第二位

对[2, 8, 1, 5, 3]这个数组排序,完整流程如下

round 1 start
2 8 1 5 3  (exchange data: 3 <-> 5)  2 8 1 3 5
2 8 1 3 5  (exchange data: 1 <-> 8)  2 1 8 3 5
2 1 8 3 5  (exchange data: 1 <-> 2)  1 2 8 3 5
round 1 finish
round 2 start
1 2 8 3 5  (exchange data: 3 <-> 8)  1 2 3 8 5
round 2 finish
round 3 start
1 2 3 8 5  (exchange data: 5 <-> 8)  1 2 3 5 8
round 3 finish
round 4 start
round 4 finish


可见第一趟将最小的1放到了第一位

为什么叫冒泡排序呢?因为上面两两交换的过程每一趟都将最小的值放到了最顶端,很像气泡上升到顶部的过程。

1. 实现

关键代码实现如下:

@Override
public int[] sort(int[] data) {
if (data == null || data.length <= 1) {
return data;
}

for (int i = 0; i < data.length - 1; i++) {
for (int j = data.length - 1; j > i; j--) {
if (data[j] < data[j - 1]) {
swap(data, j, j - 1);
}
}
}

return data;
}


具体实现可查看:

GitHub/BubleSort.java

2. 复杂度分析

从代码和原理可以看出,外层循环需要n-1次,内层循环需要n-i次,比较一次,数据操作三次。因此最坏的情况应该是整个序列时逆向的,时间复杂度为O(n²),最好的情况是序列时正序的一次扫描即可,时间复杂度为O(n)。平均时间复杂度为O(n²)。由于不需要额外空间,空间复杂度为O(1)

3. 优化

3.1 优化点一

如果某一趟没有发生过一次交换,则说明该数组已经有序,可以直接停止循环。只要加一个标识变量就可以实现。

3.2 优化点二

使用一个标识变量记录下最后一个发生交换的位置,则可以说明前面没有发生交换的序列已经有序,所以内部循环的终结点可以用这个值来作为结束点,也就是上面代码中的i值。在内部循环结束后
i=changFlag
就是这个作用。

两个优化点写入代码后如下:

@Override
public int[] sort(int[] data) {
if (data == null || data.length <= 1) {
return data;
}

//标识是否已经有序
boolean isChanged;
//标识最后一个发生变化的位置
int changFlag = 0;

for (int i = 0; i < data.length - 1; i++) {
isChanged = false;
System.out.println("round " + (i + 1) + " start");
for (int j = data.length - 1; j > i; j--) {
if (data[j] < data[j - 1]) {
swap(data, j, j - 1);
isChanged = true;
changFlag = j - 1;
}
}
//i直接设置为最后一次的交换
i = changFlag;
//如果没有改变,则证明序列已经有序
if (!isChanged) {
System.out.println("no exchange, break out loop");
break;
}
System.out.println("round " + (i + 1) + " finish");
}

return data;
}


具体实现可查看:

GitHub/BubleSort.java
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  冒泡排序 算法