【问题标题】:Why does changing the copied version of the linkedlist change the original linkedlist?为什么更改链表的复制版本会更改原始链表?
【发布时间】:2021-05-24 07:04:58
【问题描述】:
def is_palindromic_linked_list(head):

    if head is None or head.next is None:
        return True

    slow = head
    fast = head

    while fast is not None and fast.next is not None:
        fast = fast.next.next
        slow = slow.next

    head_second_half = reverse(slow) #6, 4, 2 => 2, 4, 6
    copy_head_second_half = head_second_half #<------HERE: copied linkedlist
    
    while (head is not None and head_second_half is not None):
        if head.value != head_second_half.value:
            break
        head = head.next
        head_second_half = head_second_half.next

    reverse(copy_head_second_half) #<---HERE: reversed the copied version of the linkedlist to set it back to how it was. 

    if head is None or head_second_half is None:
        return True

    return False

def reverse(head):
    
    prev = None

    while (head is not None):

        next = head.next
        head.next  = prev
        prev = head
        head = next

    return prev

这有什么意义?链表的工作方式是否与变量不同,因为更改复制版本会更改原始版本?

【问题讨论】:

  • 在大多数情况下,分配不会创建副本。
  • 链表没有被复制,只是对链表的引用。只有 1 个链表,但有 2 个变量指向它。

标签: python python-3.x linked-list palindrome


【解决方案1】:

mutable 对象发挥作用时,问题就开始了。在您的案例中,您引用的是同一个对象,这意味着每个标签都指向同一个对象。 关于这个话题有太多话要说,但我建议从here开始阅读一些东西

【讨论】:

    【解决方案2】:

    当您直接将原始列表分配给复制列表时,您正在引用它。

    你需要使用copy(),如果你的列表有其他对象,你可能需要使用deepCopy(),链接中都有解释。

    与您的示例一起使用:

    • 浅拷贝

    浅拷贝构造一个新的复合对象,然后(尽可能)将引用插入到其中找到的对象 原件。

    
        copy_head_second_half = head_second_half.copy() #<------HERE: copied linkedlist
    
    
    • 深拷贝

    深拷贝构造一个新的复合对象,然后递归地将在原始对象中找到的对象的副本插入其中。

    
        copy_head_second_half = head_second_half.deepCopy() #<------HERE: copied linkedlist
    
    

    【讨论】:

      【解决方案3】:

      如前所述,copy_head_second_half 变量获取对反向链表头节点的引用。没有节点被复制。但是请注意,列表已经被reverse 变异了,所以即使你认为你正在复制带有这个赋值的列表,也为时已晚:原始列表的变异已经发生了。

      您需要这个copy_head_second_half 变量,不是因为您需要整个列表的副本,而是因为您需要保留对该头节点的引用,而head_second_half 将指向随后的循环中的其他节点。如果没有这个复制的参考,您将丢失第二个列表的开始位置!

      的确,原始列表通过调用reverse 进行了变异,但这就是您的代码再次调用reverse 的原因:这样变异将被逆转,并且您的列表将在函数返回。

      这实际上是一个很好的做法:您不分配内存来复制列表的一半。

      【讨论】:

        猜你喜欢
        • 2020-10-04
        • 1970-01-01
        • 2015-05-06
        • 1970-01-01
        • 2017-02-20
        • 2021-11-03
        • 2015-02-02
        • 2013-09-17
        相关资源
        最近更新 更多