让我来解释一下。
首先考虑一个列表,它是“几乎”有序的。也就是说,前面几个元素已经排序好了,但最后一个元素没有排序。因此它看起来像这样:
[10, 20, 30, 50, 15]
显然,15的位置不正确。那么我们如何移动它?
key = mylist[4]
mylist[4] = mylist[3]
mylist[3] = key
这将交换15和50的位置,现在列表看起来像:
[10, 20, 30, 15, 50]
但是我们希望在循环中执行这个操作多次。实现这个需求,我们可以使用如下代码:
while ???:
key = mylist[i]
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
这个循环会每次向后移动一位,并交换两个元素,这将使得无序的位置每次向后移动一位。但我们如何知道何时停止呢?
让我们再次查看我们的列表和我们想要进行的操作:
[10, 20, 30, 50, 15]
[10, 20, 30, 15, 50]
[10, 20, 15, 30, 50]
[10, 15, 20, 30, 50]
但这次与上次不同的是什么呢?每次我们将第一个位置向后移动,都是因为15小于左边的元素,这意味着它没有排序。当不再满足条件时,我们应该停止移动。但我们可以轻松地处理这个问题:
key = mylist[i]
while key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
好的,但是如果我们现在尝试对这个列表进行排序会发生什么:
[10, 20, 1]
[10, 1, 20]
[1, 10, 20]
# 错误!!
此时会出现一些不好的情况。我们尝试检查 key < mylist[i-1],但当我们到达开头时,i = 0,这时检查的是列表的末尾。但是此时我们应该停止向左移动......
如果我们到达列表的开头,就不能再将我们的中心点/key向左移动了,因此我们应该停止。我们更新 while 循环来处理它:
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
现在我们有了一种技术可以对几乎排序好的列表进行排序。但是我们如何使用它来对整个列表进行排序呢?我们将列表分成若干部分进行排序。
[8, 2, 4, 9, 3, 6]
首先,我们对前1个元素进行排序:
[8, 2, 4, 9, 3, 6]
然后我们对前两个元素进行排序:
[2, 8, 4, 9, 3, 6]
然后我们对前三个元素进行排序
[2, 4, 8, 9, 3, 6]
等等之类的
[2, 4, 8, 9, 3, 6]
[2, 4, 8, 9, 3, 6]
[2, 3, 4, 8, 9, 6]
[2, 3, 4, 6, 8, 9]
但是我们怎样做呢?使用for循环
for j in range(len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
但是我们可以跳过第一次排序,因为只有一个元素的列表显然已经排序了。
for j in range(1, len(mylist)):
i = j
key = mylist[i]
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
mylist[i-1] = key
i -= 1
几个微小的变化虽然没有任何区别,但将我们带回到了您原始的代码。
for j in range(1, len(mylist)):
key = mylist[j]
i = j
while i > 0 and key < mylist[i-1]:
mylist[i] = mylist[i-1]
i -= 1
mylist[i] = key