【问题标题】:Variation on Bubble Sort infinite loop error冒泡排序无限循环错误的变化
【发布时间】:2019-10-18 20:32:58
【问题描述】:

在一个特定的棋盘游戏中,只有一行,它包含 N 个空格,从左到右编号为 0 到 N - 1。还有 N 个弹珠,编号从 0 到 N - 1,最初以任意顺序放置。之后,有两个动作一次只能做一个:

  • 切换:切换弹珠位置 0 和 1。
  • 旋转:移动 位置 0 的弹珠到位置 N - 1,并移动所有其他弹珠 向左一格(低一格)。

目标是按顺序排列弹珠,每个弹珠 i 在位置 i。

我编写的代码适用于发布在问题 (1 3 0 2) 上的示例,但是当我将额外的数字 4 随机添加到列表中时,while 循环永远不会终止。查看排序后的序列,它似乎在重复循环多个相同的序列。我不确定为什么它适用于一个系列但不适用于下一个系列。

奖金,我似乎无法弄清楚如何将输出打印为用空格分隔的数字与带有括号和逗号的列表。问题要求我们将输出打印为用空格分隔的数字。对此的任何帮助将不胜感激。

class MarblesBoard:
    """creates a marble board with number marbles in specific spots"""
    def __init__(self, marble_sequence):
        self.board = [x for x in marble_sequence]

    def __str__(self):
        return str(self.board)

    def __repr__(self):
        return "%r " % (self.board)

    def switch(self):
        """switch the marbles in position 0 and 1"""
        self.board[0], self.board[1] = self.board[1], self.board[0]
        return self.board

    def rotate(self):
        """Move the marble in position 0 to position N - 1, and move all other marbles one space to the left (one index lower)"""
        copy_board = self.board.copy()
        copy_board[len(self.board)-1] = self.board[0]
        for x in range(1, len(self.board)):
            copy_board[x - 1] = self.board[x]
        self.board = copy_board
        return self.board

    def is_sorted(self):
        return self.board == sorted(self.board):

class Solver:
    """solves the marble sorting game when given a marble board as input"""

    def __init__(self, MarblesBoard):
        self.steps = 0
        self.board = MarblesBoard.board
        return

    def solve(self):
        n = len(self.board)
        # print("n = ", n)
        print(self.board)
        while MarblesBoard.is_sorted(self) == False:
            if self.board[0] > self.board[1]:
                MarblesBoard.rotate(self)
                print(self.board)
                self.steps += 1
            else:
                MarblesBoard.switch(self)
                print(self.board)
                self.steps += 1
        print("total steps: ", self.steps)

关于输出,代码在此处的示例输出中运行良好:

board2 = MarblesBoard((1,3,0,2))
solver = Solver(board2)
solver.solve()

[1, 3, 0, 2]
[3, 1, 0, 2]
[1, 0, 2, 3]
[0, 2, 3, 1]
[2, 0, 3, 1]
[0, 3, 1, 2]
[3, 0, 1, 2]
[0, 1, 2, 3]
total steps:  7

但是,如果我在起跑板上添加 4:

board2 = MarblesBoard((1,3,0,2,4))
solver = Solver(board2)
solver.solve()

[1, 3, 0, 2, 4]
[3, 1, 0, 2, 4]
[1, 0, 2, 4, 3]
[0, 2, 4, 3, 1]
[2, 0, 4, 3, 1]
[0, 4, 3, 1, 2]
[4, 0, 3, 1, 2]
[0, 3, 1, 2, 4]
[3, 0, 1, 2, 4]
[0, 1, 2, 4, 3]
[1, 0, 2, 4, 3]
[0, 2, 4, 3, 1]
[2, 0, 4, 3, 1]
[0, 4, 3, 1, 2]
[4, 0, 3, 1, 2]
[0, 3, 1, 2, 4]
[3, 0, 1, 2, 4]

请注意,3 0 1 2 4 作为第二次迭代和最后列出的迭代重复。由于 while 循环的结构,由于发生相同的序列,因此执行相同的步骤并且循环无限继续。

【问题讨论】:

  • 您的is_sorted 方法可以简单地为return self.board == sorted(self.board)。很高兴您在条件为 True 时没有返回 False
  • @dumdum——只有当它完全回答了你的问题。

标签: python while-loop bubble-sort


【解决方案1】:

那么,冒泡排序到底是如何变化的呢?大多数排序都有一种方法将已排序和未排序的数据保存在不同的区域中,以便清楚已经排序的数据。这种似乎没有这样做。

看起来切换发生的唯一条件是board[0] > board[1]。真的只有这些吗?

我对代码的建议如下:

class MarblesBoard:

    def __init__(self, marble_sequence):
        self.board = [x for x in marble_sequence]

这不是有点多余吗?为什么不:

class MarblesBoard:

    def __init__(self, marble_sequence):
        self.board = marble_sequence

我似乎无法弄清楚如何将输出打印为数字 用空格隔开

这将带我了解__str__ 的实现:

def __str__(self):
        return str(self.board)

那不行。看看我尝试在 shell 中执行类似操作时返回的字符串:

>>> str([1, 2, 3])
'[1, 2, 3]'
>>> 

你最好使用str.join

def __str__(self):
    return " ".join(map(str, self.board))

您的switch 方法看起来不错,只是您不需要从中返回任何内容。只需交换元素即可。

如果我对rotate方法的理解正确,可以简化:

def rotate(self):
    self.board.append(self.board.pop(0))

同样,您不需要从此函数返回任何内容。

您的is_sorted 也可以简化:

def is_sorted(self):
    return self.board == sorted(self.board)

我还可能会在您的 MarblesBoard 类中添加一个名为 should_rotate 的方法,该方法返回 TrueFalse,具体取决于求解器是否应该旋转或切换。它打算稍后由求解器使用:

def should_rotate(self):
    return self.board[0] > self.board[1]

接下来,Solver 类。首先是__init__方法:

通过命名参数MarblesBoard,(与类同名),您将隐藏类的标识符 - 所以我不会调用该参数。我认为marbles_board 是一个更好的名字。

其次,我认为没有充分的理由在 __init__ 中明确地将 steps 设为实例变量,因为您使用它的唯一位置是在 solve 方法中。我现在就摆脱它。

第三,我认为将self.board 绑定到MarblesBoard 实例的board 对象不是一个好主意。如果你的Solver 类基本上只是围绕MarblesBoard.board,那么你甚至可以不制作这个类,而只是在MarblesBoard 类中完成所有的解决方案。同样,您不需要从您的 __init__ 中显式地 return

class Solver:

    def __init__(self, marbles_board):
        self.marbles_board = marbles_board

solve 也可以简化一点:

def solve(self):

    number_of_steps = 0

    while not self.marbles_board.is_sorted():
        if self.marbles_board.should_rotate():
            self.marbles_board.rotate()
        else:
            self.marbles_board.switch()
        number_of_steps += 1
    print(f"Number of steps: {number_of_steps}")

很有趣的是,您对 solve 的实现工作得和它一样好,看看您如何将 selfSolver 对象)作为 rotateswitch 的参数传递方法。

【讨论】:

  • 我的理解是,传统的冒泡排序会查看索引 [0] 和 [1] 并在移动到索引 [1] 和 [2] 之前对其进行排序并对其进行排序......一直到索引[n-1] 和 [n]。然后它重复这个直到索引 [n-2] 和 [n-1] 等等。此版本仅切换索引 [0] 和 [1],但可以使用旋转功能向下移动列表。我会把它比作一个改变的参考框架。不是将索引向下移动,而是移动列表。
  • 感谢您的帮助!加 4 的时候还是有无限的 while 循环,但是这段代码现在更容易阅读了。
猜你喜欢
  • 2012-09-17
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 2016-08-31
  • 2018-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多