冒泡排序的原理不多说,先看python版的bubblesort:
#!/usr/bin/python
import sys
n = len(sys.argv) - 1
for i in range(n, 0, -1): # n to 1
for j in range(1, i): # 1 to i-1
if int(sys.argv[j], 10) > int(sys.argv[j+1], 10): # [C]
tmp = sys.argv[j] # [M]
sys.argv[j] = sys.argv[j+1] # [M]
sys.argv[j+1] = tmp # [M]
print sys.argv
算法最佳情况下只进行数据的比较,即初始数组已经排好序,只执行代码中[C]步骤,一共进行n*((n+1)/2*1)次,此时时间复杂度为O(N^2)。算法最差情况下要进行数据的比较[C]和移动[M],虽然时间复杂度同样为O(N^2),但是每次比较之后都会进行三次数据移动,一共执行n*((n+1)/2*4)次比较和移动。
传统的冒泡排序缺点在于排序类似[2,3,4,5,1]数列的时候,要循环多次,如下所示:
[2,3,4,5,1]
[2,3,4,1,5]
[2,3,1,4,5]
[2,1,3,4,5]
[1,2,3,4,5]
可以看出,只是为了移动一个数而不得不分成四次完成,如果一开始从右往左遍历,一次排序即可完成,因此我们可以加上一个反向遍历的冒泡排序,当从左遍历到右边之后不是立即再从左往右遍历,而是从右边往左边做冒泡排序,代码如下:
#!/usr/bin/python
import sys
n = len(sys.argv) - 1
for i in range(n, 0, -1): # n to 1
for j in range(1, i): # 1 to i-1
if int(sys.argv[j], 10) > int(sys.argv[j+1], 10): # [C]
tmp = sys.argv[j] # [M]
sys.argv[j] = sys.argv[j+1] # [M]
sys.argv[j+1] = tmp # [M]
# shakersort, this part can improve bubblesort in some cases
for j in range(i - 1, 0, -1): # i-1 to 1
if int(sys.argv[j], 10) > int(sys.argv[j+1], 10): # [C]
tmp = sys.argv[j] # [M]
sys.argv[j] = sys.argv[j+1] # [M]
sys.argv[j+1] = tmp # [M]
print sys.argv
算法最佳情况下只进行数据的比较,即初始数组已经排好序,只进行代码中[C]步骤,一共进行n*((n+1)/2*2)次,此时时间复杂度为O(N^2)。算法最差情况下要进行数据的比较[C]和移动[M],虽然时间复杂度同样为O(N^2),但是每次比较之后都会进行三次数据移动,一共进行n*((n+1)/2*8)次比较和移动。
对[2,3,4,5,1]数列进行排序,过程如下:
[2,3,4,5,1]
[1,2,3,4,5]
[1,2,3,4,5]
[1,2,3,4,5]
[1,2,3,4,5]
改进的优点:对类似上述数列的排序进行排序时,减少了数据的移动。
缺点:增加了比较的次数。
可能的改进:可以看出加入shakersort之后对[2,3,4,5,1]进行排序时,数列很快就被排好序,如果能提前检测到数列已经被排好序,那么就可以提前停止算法,这样大大减少比较的次数和算法执行的时间。
以下是对算法进行改进后的代码:
#!/usr/bin/python
import sys
n = len(sys.argv) - 1
l = 1
r = n
for i in range(l, r/2+1): # 只需要进行n/2次双向冒泡排序
is_sorted = 1
for j in range(l, r): # 从左往右冒泡
if int(sys.argv[j], 10) > int(sys.argv[j + 1], 10):
tmp = sys.argv[j]
sys.argv[j] = sys.argv[j + 1]
sys.argv[j+1] = tmp
is_sorted = 0 # 如果还存在数据交换,说明数列还没排好序
# shakersort, this part can improve bubblesort
for j in range(r - 1, l, -1): # 从右往左冒泡
if int(sys.argv[j], 10) < int(sys.argv[j - 1], 10):
tmp = sys.argv[j]
sys.argv[j] = sys.argv[j - 1]
sys.argv[j - 1] = tmp
is_sorted = 0 # 如果还存在数据交换,说明数列还没排好序
if(is_sorted): # 检查数列是否已经排好序
break;
l = l + 1
r = r - 1
print sys.argv
用以上算法对数列[1,2,3,4,5,6,7,0]进行排序,输出如下:
[0,1,2,3,4,5,6,7]
此时达到冒泡排序的最优状态,即分别对[7,0,1,2,3,4,5,6]和[1,2,3,4,5,6,7,0]排序都是一次循环结束战斗。