冒泡排序 |
通过对排序序列从前向后(从下标最小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移到后部,就像水底下的气泡一样逐渐向上冒
如果一趟下来没有进行过交换就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换,从而减少不比较的比较
思路
有这样一个数组arr {5,6,4,3,2,1},使用冒泡排序从小到大
第一趟排序:
5 6 4 3 2 1
5 4 6 3 2 1
5 4 3 6 2 1
5 4 3 2 6 1
5 4 3 2 1 6
最大的6已经交换到了最右边
第二趟排序:
4 5 3 2 1 6
4 3 5 2 1 6
4 3 2 5 1 6
4 3 2 1 5 6
4 3 2 1 5 6
最大的5交换到6的后面
第三趟排序:
3 4 2 1 5 6
3 2 4 1 5 6
3 2 1 4 5 6
3 2 1 4 5 6
最大的4交换到5的后面
第四趟排序
2 3 1 4 5 6
2 1 3 4 5 6
2 1 3 4 5 6
最大的3交换到4的后面
第五趟排序
1 2 3 4 5 6
1 2 3 4 5 6
最大的2交换到3的后面,然后最后一次比较没有发生交换,冒泡结束
总结:
- 冒泡排序一共进行数组元素个数-1趟交换
- 每趟排序的次数在逐渐减少
推导
声明数组arr
根据上面的思路,第一趟交换进行了arr.length-1次,如果数组的第一个元素大于第二个元素,那么就发生交换,代码如下:
第二趟就只比较arr.length-2次,因为最大的数已经被交换到最右边了
第三趟、第四趟、第五趟都同理可得,比较的数越来越少,因为比较的趟数
等于数组元素个数-1,所以当数组元素个数为n时,趟数为n-1,也就是
假设趟数为i,只要在上面代码外面套一层for循环,然后让i去递增即可,所以
最后代码实现如下:
实现
优化
优化主要是根据思路而来,思路中,每趟排序有多次,而当有一次比较没有发生交换,就意味着不需要再进行比较了
速度测试
增加一个80000个 数的数组
获取当前时间
获取排序后时间
优化之后的执行结果,13秒
注释优化的代码
优化之前是15秒
需要多次执行再比较,优化之后的时间大多数是要小于优化之前的时间的,这是因为CPU有其他情况,不一定每次执行时间一致
小结
- 时间复杂度
优化之前的时间复杂是O(N²),优化之后 O(N) - 空间复杂度,就是借用了flag这个变量需要申请空间
最优的空间复杂度,同样,就是不需要借用第三方内存空间,则复杂度为0
最差的空间复杂度就是开始元素逆序排序,每次都要借用一次内存,按照实际的循环次数,为O(N)
冒泡排序是稳定的,因为每次都是相邻的两个两两交换