【问题标题】:Sorting a linked list (swapping nodes)对链表进行排序(交换节点)
【发布时间】:2021-05-24 09:59:50
【问题描述】:

我正在尝试对包含此类节点的 LinkedList 进行排序:

class Node:
   def __init__(self, data, next=None):
       self.data, self.next = data, next

这个想法是获取一个序列(列表/元组/字符串),从中创建一个 LinkedList:

def __init__(self, seq):
    self.front = self.Node(None)
    node = self.front
    for item in seq:
        node.next = self.Node(item)
        node = node.next

排序的逻辑是在每次迭代中遍历链表,将每个项目与第一个项目进行比较,如果它更小/更大,则执行交换,继续遍历链表并进行相同的比较和操作.此处显示:

    def min_sort(self, reverse):
        self.count = 0
        first = self.front
        while first.next is not None:
            print(self.get_list())
            self.progress(first, reverse)
            self.count += 1
            first = first.next

    def progress(self, first, reverse):
        node = first
        if (node is None): return
        while True:
            node = node.next
            if node is None or node.next is None: break

            if (reverse):
                if (first.next.data < node.next.data):
                    self.vymen(first, node, node.next)
            else:
                if (first.next.data > node.next.data):
                    self.vymen(first, node, node.next)

问题在于交换本身(函数 self.vymen(...)),它通常使用基本的数字 LinkedList 工作,但是当加载一个字符串时,例如“我用 Python 编码”,空格不会交换到正确的位置,从而使整个结果变得混乱。 交换本身是:

    def vymen(self, first, prev, swap):
        prevX, currX, prevY, currY = first, first.next, prev, swap

        if (self.front.next.data == swap.data): return
        if (currX is None or currY is None): return

        if (currX != prevY):
            if (prevX is not None): prevX.next = currY
            else: self.front = currY

            if (prevY is not None): prevY.next = currX
            else: self.front = currX

            temp = currX.next
            currX.next = currY.next
            currY.next = temp

        else:
            temp = currY.next
            currX.next = temp
            currY.next = currX
            prevX.next = currY

正如我所见,这实际上只是空格的问题,我不明白是什么问题,因为它在开始时交换了第一个空格,而不是其余的。如果有人能够指出错误或告诉我发生了什么,我将不胜感激:)

【问题讨论】:

  • 请提供您所进行的实际调用,其中包含造成问题的特定输入,并具体说明您获得的输出以及您的期望。

标签: python sorting linked-list


【解决方案1】:

您的代码中有两个问题:

  • vymen中的以下语句是麻烦的原因:

    if (self.front.next.data == swap.data): return
    

    其目的是在交换节点的数据相等时避免不必要的交换。但是它不应该引用self.front.next,而是curX——因为那个是要交换的节点:

    if currX.data == currY.data:
        return
    
  • 紧随其后的if 条件此时没有用处:

    if (currX is None or currY is None): return
    

    ...因为此时我们已经引用了swap.data(即currY.data)。因此,如果这确实可行,则应在引用 currY.datacurrX.data 之前对其进行检查。所以结合之前的if

    if currX is None or currY is None or currX.data == currY.data:
        return
    
  • progress 中的主循环将在两个 连续(!) 节点交换时跳过一个节点。在这种情况下,在调用vymen 之前,node 将变为currX,它将跳过node.next。因此调用之后,node 仍将引用同一个节点,但它在列表中的位置更远。结果,有一个节点不会有循环的迭代。这是导致错误输出的原因,即使是纯数字也是如此。为了解决这个问题,您可以调整vymen,使其返回node 在调用开始时处于相同位置的节点。然后调用者应该将该引用重新分配给它的node 变量。

其他一些评论:

  • 在 Python 中,不需要在 if 条件周围加上括号

  • vymen 中,以下条件应始终为真:

    if (prevX is not None): prevX.next = currY
    else: self.front = currY
    

    这不应该是真的,因为您已经将链表设计为在其前面有一个哨兵节点(具有值None)。所以你甚至不希望self.front = currY 执行! prevX 永远不应该是 None。在您调用此函数的方式中,它也绝不是 None。因此,只需删除此构造并分配:

    prevX.next = currY
    

    后面的if..else 也应该这样。

  • vymen 不应该需要它的最后一个参数 (swap),因为它应该始终是 prev.next 的值。所以函数可以这样开始:

    def vymen(self, first, prev):
        prevX, currX, prevY, currY = first, first.next, prev, prev.next
    

    调用将是(还要注意返回值的分配):

    node = self.vymen(first, node)
    
  • 很遗憾,在vymen的函数头之后,你定义了与firstprev完全相同的新变量:prevXprevY。为什么不立即这样命名参数变量呢?

  • 很遗憾,在progress 中有一个ifbreak 作为while True 正文中的第一个语句。您可以更好地重写它,以便在while 语句中具有条件

综合来看,这是两个有问题的方法的结果代码:

    def progress(self, first, reverse):
        if first is None or first.next is None:
            return
        node = first.next
        while node.next:  # Use a condition to exit instead of break
            if reverse:
                if first.next.data < node.next.data:
                    # Take the return value, and pass one argument less
                    node = self.vymen(first, node)  
            else:
                if first.next.data > node.next.data:
                    # Take the return value, and pass one argument less
                    node = self.vymen(first, node)
            node = node.next

    def vymen(self, prevX, prevY):  # Use the desired variable names
        # No need for the swap argument
        currX, currY = prevX.next, prevY.next

        # Corrected comparison of the two nodes' data, and put the 
        #   conditions in the right order:
        if currX is None or currY is None or currX.data == currY.data:
            return prev # return the node at the position of prev 

        if currX != prevY:
            # Make the following assignments unconditionally
            prevX.next = currY
            prevY.next = currX

            temp = currX.next
            currX.next = currY.next
            currY.next = temp
            # Return the reference of the node that is in the position
            #    of prev: it is still in the same position:
            return prev
        else:
            temp = currY.next
            currX.next = temp
            currY.next = currX
            prevX.next = currY
            # Return the reference of the node that is in the position
            #    of prev: it has moved, so now it is...:
            return currY

【讨论】:

  • 毕竟我发现了一些问题,你提到了。无论如何,这工作得很好,直到我得到一个充满 500 多个随机字符串的链表,它在最大递归深度上失败(超时错误)。我一定会看看这个,非常感谢你! :)
  • 好的。仅此代码不能产生最大递归深度错误。没有递归。您可以看到它运行 here,输入字符串为 900 个字符。运行并输出排序列表需要 2 秒。 get_list 的实现可能是递归的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-02
  • 2014-09-23
相关资源
最近更新 更多