冒泡排序
冒泡排序(Bubble Sort),是一种简单的排序算法。
算法名字由来:越小的元素会经由交换慢慢 "浮" 到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
算法重复遍历要排序的元素列,依次比较两个相邻的元素,如下图所示。如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。遍历元素的工作是重复的进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
冒泡排序有两种代码实现方式:
-
将最小的元素 冒出来 -
将最大的元素 沉下去
冒出最小元素
执行过程如下:
-
从后往前,依次比较两个相邻元素 -
如果 前面的元素 比 后面元素大,则交换两个元素 -
对每一对相邻元素做同样的工作,从最后一对到开始的第一对 -
当第一遍执行完后,第一个元素就是最小的元素 -
针对所有的的元素重复上述步骤,除了第一个 -
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
以[4,7,2,5,1,3]
为例,将最小的元素冒出来的示意图如下
从后往前依次比较两个相邻元素,数组中最小的元素是1
每次比较过后,1
都会被交换到更靠前的位置 等到第5步过后,数组中的第一个元素就是最小的元素了。
还是以[4,7,2,5,1,3]
为例,完整的排序过程如下:上图中
-
第一趟遍历后,我们将最小的元素 冒出到第一位,也就是排到了数组的第一位 -
第二趟后,第二小的元素被排到了数组的第二位 -
第三趟后,第三小的元素被排到了数组的第三位 -
第四趟后,第四小的元素被排到了数组的第四位 -
第五趟后,第五小的元素被排到了数组的第五位
这就是冒泡排序的特点,每次都把最小的元素往前挪。
由于上面数组一共有6个元素,需要5趟比较,所以对于有N个元素的数组来说,需要比较N-1趟。
数组[4,7,2,5,1,3]
,完整的排序动画如下图所示:
java代码:
public class BubbleSort {
public void sort(int[] arr) {
if(arr==null || arr.length==0) {
return;
}
int n = arr.length;
//外层指定了需要排序多少趟,N个元素需要N-1趟排序
for(int i=0;i<n-1;++i) {
//从最后一个元素一直比较到第i个元素,初始的时候i=0
//第一趟后第一个元素就是最小的,
//之后i=1即第二趟后,第二个元素是第二小的
//i=3,第三趟后第三个元素第三小
for(int j=n-1;j>i;--j) {
//如果前面的元素比后面的大,就交换两个元素
if(arr[j-1] > arr[j]) {
int tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
}
}
}
}
}
python代码:
class BubbleSort(object):
def sort(self,arr):
if not arr:
return
n = len(arr)
# 外层指定了需要排序多少趟,N个元素需要N-1趟排序
for i in xrange(n-1):
# 从最后一个元素一直比较到第i个元素,初始的时候i=0
# 第一趟后第一个元素就是最小的,
# 之后i=1即第二趟后,第二个元素是第二小的
# i=3,第三趟后第三个元素第三小
for j in xrange(n-1,i,-1):
# 如果前面的元素比后面的大,就交换两个元素
if arr[j] < arr[j-1]:
arr[j],arr[j-1] = arr[j-1],arr[j]
沉下最大元素
沉下最大元素和冒出最小元素很类似,冒出最小是将小元素往前挪动,而沉下最大元素是将大元素往后挪动。
也就是将最大的元素挪动到数组的后面
执行过程如下:
-
从前往后,依次比较两个相邻元素 -
如果 前面的元素 比 后面元素大,则交换两个元素 -
对每一对相邻元素做同样的工作,从开始的第一对到最后一对 -
当第一遍执行完后,最后一个元素就是最大的元素 -
针对所有的的元素重复上述步骤,除了最后一个 -
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
以[4,7,2,5,1,3]
为例,将最大的元素沉下去的示意图如下
从前往后依次比较两个相邻元素,数组中最大的元素是7
每次比较过后,7
都会被交换到更靠后的位置 等到第5步过后,数组中的最后一个元素就是最大的元素了。
数组[4,7,2,5,1,3]
,完整的排序动画如下图所示:
上图中
-
第一趟遍历后,我们将最大的元素 沉到到最后一位,也就是排到了数组的末尾 -
第二趟后,第二大的元素被排到了数组的倒数第二位 -
第三趟后,第三大的元素被排到了数组的倒数第三位 -
第四趟后,第四大的元素被排到了数组的倒数第四位 -
第五趟后,第五大的元素被排到了数组的倒数第五位
[4,7,2,5,1,3]
这个数组,完整的排序动画如下图所示:
java代码:
public class BubbleSort {
public void sort(int[] arr) {
if(arr==null || arr.length==0) {
return;
}
int n = arr.length;
//外层指定了需要排序多少趟,N个元素需要N-1趟排序
for(int i=0;i<n-1;++i) {
//从第一个元素一直比较到第n-1个元素,第一趟j<n-1
//第二趟,从第一个元素比较到n-2个元素,j<n-2
//第三趟,从第一个元素比较到n-3个元素,j<n-3
for(int j=0;j<n-i-1;++j) {
//如果前面的元素比后面的大,就交换两个元素
if(arr[j] > arr[j+1]) {
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
}
python代码:
class BubbleSort(object):
def sort(self):
if not arr:
return
n = len(arr)
# 外层指定了需要排序多少趟,N个元素需要N-1趟排序
for i in xrange(n-1):
# 从第一个元素一直比较到第n-1个元素,第一趟j<n-1
# 第二趟,从第一个元素比较到n-2个元素,j<n-2
# 第三趟,从第一个元素比较到n-3个元素,j<n-3
for j in xrange(n-i-1):
# 如果前面的元素比后面的大,就交换两个元素
if arr[j] > arr[j+1]:
arr[j],arr[j+1] = arr[j+1],arr[j]
细节分析和优化
无论是冒出最小元素,还是沉下最大元素,都需要执行N-1趟比较,也就是外层循环是执行N-1次。
这里的N是数组长度。
外层循环需要执行N-1次,内层循环是受到外层循环控制的
-
第一趟会执行 N-1次比较,这之后数组中第一个元素就是最小的了 -
第二趟需要执行 N-2次比较,因为最小的元素已经找到了,我们需要找第二小的,第二趟后数组中第二个元素是最小的 -
第三趟需要执行 N-3次比较 -
最后一趟需要执行 1次比较
冒泡排序最坏的情况下需要执行N-1趟,每趟比较N-i次,(1≤i≤n-1)
每次比较要移动记录三次来达到交换记录位置
所以,比较(C)的次数,移动(M)的次数分别为:
冒泡排序的最坏时间复杂度为 O(N^2)
冒泡排序总的平均时间复杂度为O(N^2)
由于没有用到其他辅助空间,空间复杂度为O(1)
对于一个完全有序的数组,上述代码仍然需要执行O(N^2)次
这样就完全没必要了,我们可以增加一个优化,如果一趟下来如果没有发生任何元素交换,那么就说明整个数组是有序的,可以直接退出循环。
这样当输入一个有序的数组时,冒泡排序的时间复杂度就是 O(N)
优化后的代码如下
java代码:
public class BubbleSort {
public void sort(int[] arr) {
if(arr==null || arr.length==0) {
return;
}
int n = arr.length;
for(int i=0;i<n-1;++i) {
//定义一个是否交换的变量,如果内层循环中没有出现过交换
//说明整个数组都是有序的,直接退出外层循环即可
boolean isSwap = false;
for(int j=n-1;j>i;--j) {
if(arr[j-1] > arr[j]) {
int tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
isSwap = true;
}
}
//如果没有发生过交换,说明整个数组是有序的,直接退出外层循环
if(!isSwap) {
break;
}
}
}
}
python代码:
class BubbleSort(object):
def sort(self):
if not arr:
return
n = len(arr)
for i in xrange(n-1):
# 定义一个是否交换的变量,如果内层循环中没有出现过交换
# 说明整个数组都是有序的,直接退出外层循环即可
isSwap = False
for j in xrange(n-i-1):
if arr[j] > arr[j+1]:
arr[j],arr[j+1] = arr[j+1],arr[j]
isSwap = True
# 如果没有发生过交换,说明整个数组是有序的,直接退出外层循环
if not isSwap:
break
参考:
排序算法可视化:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
看完本文有收获?请转发分享给更多人
好文章,我在看❤️
本文分享自微信公众号 - 大话算法(algorithm2pic)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
来源:oschina
链接:https://my.oschina.net/u/4117940/blog/4759953