我是Python新手,在Python中学习数据结构。我试图在python中实现一个冒泡排序算法,我做得很好,但我得不到正确的结果。然后我找到了一些教程,在那里我看到他们首先设置一个基础范围进行检查。
因此python中range
的语法是:
range([start], stop[, step])
冒泡排序算法是:
def bubbleSort(alist):
for i in range(len(alist) - 1, 0, -1):
for j in range(i):
if alist[j] > alist[j+1]:
temp = alist[j]
alist[j] = alist[j+1]
alist[j+1] = temp
return alist
print(bubbleSort([5, 1, 2, 3, 9, 8, 0]))
我理解算法的所有其他逻辑,但我无法理解为什么循环从列表的末尾开始直到列表的第一个元素:
for i in range(len(alist) - 1, 0, -1):
为什么这会反向遍历列表?此循环的主要目的是仅设置范围条件,以便为什么我们不能像这样从第一个元素遍历到len(list) - 1
:
for i in range(0, len(alist) - 1, 1):
答案 0 :(得分:2)
在您的代码中,索引i
是内部循环在交换元素时将考虑的最大索引。冒泡排序的工作方式是交换兄弟元素以将最大元素移动到右边。
这意味着在第一次外部迭代(或内部循环的第一个完整循环)之后,列表的最大元素位于列表的远端。所以它已经在正确的位置,不需要再次考虑。这就是为什么在下一次迭代中,i
少一个以跳过最后一个元素,只查看项0..len(lst)-1
。
然后在下一次迭代中,最后两个元素将被正确排序,因此它只需要查看项0..len(lst)-2
,依此类推。
所以你想减少 i
,因为列表末尾的越来越多的元素已经处于正确的位置,不需要再查看了。你不有来做那件事;你也可以一直让内循环上升到最后,但你不需要,所以你可以跳过几次迭代而不去做。
我问为什么我们在
len(list)-1,0
这样的列表中反向。为什么我们不像0,len(list)-1
那样前进?
我希望上面的解释已经涵盖了这一点,但让我们详细介绍一下。尝试在外部循环的末尾添加print(i, alist)
。因此,您可以获得i
的每次迭代的结果:
>>> bubbleSort([5, 1, 3, 9, 2, 8, 0])
6 [1, 3, 5, 2, 8, 0, 9]
5 [1, 3, 2, 5, 0, 8, 9]
4 [1, 2, 3, 0, 5, 8, 9]
3 [1, 2, 0, 3, 5, 8, 9]
2 [1, 0, 2, 3, 5, 8, 9]
1 [0, 1, 2, 3, 5, 8, 9]
如您所见,列表将从右到左排序。这适用于我们的索引i
,这将限制内循环的范围:例如,对于i = 4
,我们在结尾处已经有3个已排序的元素,因此内部循环只需要查看在前4个元素。
现在,让我们尝试更改range
以转向另一个方向。循环将是for i in range(0, len(alist))
。然后我们得到这个结果:
>>> bubbleSort([5, 1, 3, 9, 2, 8, 0])
0 [5, 1, 3, 9, 2, 8, 0]
1 [1, 5, 3, 9, 2, 8, 0]
2 [1, 3, 5, 9, 2, 8, 0]
3 [1, 3, 5, 9, 2, 8, 0]
4 [1, 3, 5, 2, 9, 8, 0]
5 [1, 3, 2, 5, 8, 9, 0]
6 [1, 2, 3, 5, 8, 0, 9]
如您所见,这根本没有排序。但为什么? i
仍限制内循环的走向,因此在i = 1
,循环只会查看第一对并对其进行排序;其余的将保持不变。在i = 2
,循环将查看前两对并交换它们(一次!);其余的将保持不变。等等。当内循环可以到达最后一个元素(仅在最后一次迭代时)时,没有足够的迭代来将零(也恰好是最小元素)交换到最左边。
这又是因为冒泡排序首先将最大元素排序到最右边。所以我们必须通过使内循环能够完全到达右侧来启动算法。只有当我们确定这些元素处于正确的位置时,我们才能停止走这么远。
使用一种方式来使用递增外循环:首先对最小元素进行排序。但这也意味着我们必须在最右侧启动内循环,以确保在查找最小元素时检查所有元素。所以我们必须让这些循环朝着相反的方向发展。
答案 1 :(得分:0)
这是因为当您从列表的开头到结尾时,最终结果是列表中的最后一项将被排序(您已将最大的项目冒泡到最后) 。因此,当您执行下一个冒泡时,您不希望在列表中包含最后一项(您知道它已经在正确的位置)。这意味着您需要排序的列表变得更短,从结束开始并向下开始。在此代码中,i
始终是剩余未排序列表的长度。
答案 2 :(得分:0)
您可以将其用于:
for i in range(0,len(alist)-1,1):
但是你应该改变你的第二次迭代:
for j in range(0,len(alist)-i,1):
我认为在第一行中使用反向迭代的目的是简化第二次迭代。这是使用python
的优点作为@Jeremy McGibbon的回答,冒泡排序背后的逻辑是避免j
到达"排序部分"在列表的后面。使用示例代码时,j
范围将随着i
的值减少而减少。当您将i
更改为增加时,您应该以不同方式处理j
次迭代
答案 3 :(得分:0)
您可以编写以下代码
lst = [9,6,5,7,8,3,2,1,0,4]
lengthOfArray = len(lst) - 1
for i in range(lengthOfArray):
for j in range(lengthOfArray - i):
if lst[j] > lst[j + 1]:
lst[j], lst[j + 1] = lst[j + 1], lst[j]
print(lst)