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

问题描述 投票:0回答:4

我是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):
python sorting bubble-sort
4个回答
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,循环将查看前两对并交换它们(一次!);其余的将保持不变。等等。当内循环可以到达最后一个元素(仅在最后一次迭代时)时,没有足够的迭代来将零(也恰好是最小元素)交换到最左边。

这也是因为冒泡排序的工作原理是首先将最大的元素排序到最右边。所以我们必须通过使内循环能够完全到达右侧来启动算法。只有当我们确定这些要素处于正确的位置时,我们才能停止这么远。

有一种方法可以使用递增外循环:首先对最小元素进行排序。但这也意味着我们必须在最右侧启动内循环,以确保在查找最小元素时检查所有元素。所以我们必须让这些循环朝着相反的方向发展。


0
投票

这是因为当你从列表的开头到结尾时,最终的结果是列表中的最后一项将被排序(你已经将最大的项目冒泡到最后)。因此,当您执行下一个气泡时,您不希望在列表中包含最后一项(您知道它已经在正确的位置)。这意味着您需要排序的列表变得更短,从结束开始并向下开始。在此代码中,i始终是剩余未排序列表的长度。


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迭代


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)
© www.soinside.com 2019 - 2024. All rights reserved.