为什么气泡排序中的范围循环会反转?

时间:2017-09-19 06:26:44

标签: python sorting bubble-sort

我是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):

4 个答案:

答案 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)