我有两个插入排序的实现。第一个是我的java教科书中的示例的转录(尽管有while
循环而不是java for
循环)
def insertion_sort(array):
for i in range(1,len(array)):
j = i
while j > 0 and array[j] < array[j-1]:
array[j],array[j-1] = array[j-1], array[j]
j=j-1
return array
第二个似乎是一个更加pythonic的实现。
def insertion_sort2(array):
for i in range(1,len(array)):
for j in range(i-1,-1,-1):
if array[j+1] < array[j]:
array[j+1],array[j] = array[j],array[j+1]
else:
break
return array
在对两者进行计时之后,当列表已经排序或非常接近排序时,似乎第二个慢得多(慢3到4倍)。然而,随着反转次数的增加,第二次实施似乎占了上风(快10-15%)。我只是想知道是否有人可以解释造成这种差异的原因。谢谢!
编辑:这是我用来创建随机列表的功能。
def rand_list(length):
return [random.randint(0,9*length) for _ in range(length)]
如果我想要一个部分排序的列表,我只需拨打list(range(length1)) + rand_list(length2)
。
至于计算运行时间,我使用了%timeit
工具和两次datetime.now()
次呼叫之间的差异。他们都给出了非常一致的结果。另外我只想强调一点,我每次都要创建一个新列表,而不是对已排序的列表进行排序。
答案 0 :(得分:1)
我能够重现你的时间。对于随机数据或反向排序数据, insertion_sort2 比Python3.6上的 insertion_sort 快一点。但是,如您所述,对于已经排序的数据, insertion_sort2 的速度要慢三倍。
第一种情况(随机或排序数据略快)的原因是 range_iterator 对象比手动编写j=j-1
和{更快地生成递减整数(使用内部C代码) {1}}这两个都是纯python步骤。因此,一旦for循环被预热,它比while循环等效运行得快一点。
第二种情况(排序数据慢得多)的原因是,当迭代次数为零时,while循环比等效for循环便宜。这是因为while循环没有设置成本。等效for循环仍然必须创建范围对象和 range_iterator 对象,然后才能找出没有迭代的对象。因此,while循环在空或几乎为空时击败for循环,因为它们避免了设置成本。