【问题标题】:Original linked list changed原来的链表改变了
【发布时间】:2021-07-16 08:08:17
【问题描述】:

一旦我尝试反转链接列表的后半部分,main 中的原始链接列表会发生变化,但我不明白到底如何。如果有人能给我详细的解释,我将不胜感激。我在代码中留下了一些 cmets 来解释我不确定发生了什么。

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



def is_palindromic_linked_list(head):  
  if head is None or head.next is None:
    return True

  # find middle of the LinkedList
  slow, fast = head, head
  while (fast is not None and fast.next is not None):
    slow = slow.next
    fast = fast.next.next

  '''
  Here I reverse the second half of the link list.

  The variable slow points to the second half of the link list and
  the reversed linked list is now head_second_half.
  
  If I print out each node, in link list head, every node prints out from the
  original link list on this line before the reversal.
  '''

  head_second_half = reverse(slow)  # reverse the second half
  # store the head of reversed part to revert back later

  '''
  Here although I am passing slow into the reverse function to reverse the second
  half of the link list my link list head gets modified and I can see this because
  by printing out all nodes from link list head on this line after the reversal I
  seem to only get the first half of the link list 
  '''

  copy_head_second_half = head_second_half

  # compare the first and the second half
  while (head is not None and head_second_half is not None):
    if head.value != head_second_half.value:
      break  # not a palindrome

    head = head.next
    head_second_half = head_second_half.next

  reverse(copy_head_second_half)  # revert the reverse of the second half
  
  if head is None or head_second_half is None:  # if both halves match
    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


def main():
  head = Node(2)
  head.next = Node(4)
  head.next.next = Node(6)
  head.next.next.next = Node(4)
  head.next.next.next.next = Node(2)

  print("Is palindrome: " + str(is_palindromic_linked_list(head)))

  head.next.next.next.next.next = Node(2)
  print("Is palindrome: " + str(is_palindromic_linked_list(head)))


main()

我在上面有一些评论,解释了我对正在发生的事情的理解所遇到的问题。我最初的想法是只拥有一个具有反向链接列表的后半部分和其余代码的变量,而不会恢复到链接列表的原始顺序。这不起作用,因为当我在 main 中第二次调用 is_palindromic_linked_list(head) 时,链接列表已被修改并且没有属性 .next

据我了解,变量slow 是一个指向链表后半部分开始的内存地址的指针,因此,当我反转链表的后半部分时,我的原始链表得到也修改了?如果是这种情况,那么详细情况会发生什么,因为我无法理解如何恢复反转以某种方式保持原始链表在 main 中保持不变。我的意思是,在我的main 函数中,如果我要从链接列表头打印出每个节点而不恢复is_palindromic_linked_list 函数中的反转,则链接列表会更改,因此在某些时候不包含@ 987654328@ 所以我第二次调用这个函数时会发生错误,但是通过反转链表它可以工作。

我确实知道涉及地址,但我不完全了解这里发生了什么,因为我在分离链接列表的后半部分时看到了它,所以无论我对这个链接列表做什么,我认为都会与原始的,所以我的意思是通过分离它,我可以看到我的原始链接列表现在只包含前半部分并再次反转这个分离的链接列表(我认为现在与我的原始链接列表无关)以某种方式保留了我的最初的原始链表。

我不确定我是否有意义。我正在努力解释我的思考过程,非常希望得到澄清。

【问题讨论】:

  • 查看如何创建minimal reproducible example
  • 我会的。我现在不在我的电脑前,因为我已经在这工作了好几个小时了,但是一旦我早上回到电脑上,我就会更新代码。谢谢
  • 我更改了我的帖子,但我从@trincot 的回复中了解到。实际上我也有关于这段代码的问题,但有点不同,所以我在另一篇文章中包含了我的问题的一个最小示例。

标签: python memory linked-list


【解决方案1】:

当我反转链表的后半部分时,我原来的链表也会被修改?

是的,因为节点集合是相同的:不创建新节点,仅修改(它们的next 属性)。因此,当您在列表的后半部分修改节点时,这当然会影响列表。

它可以帮助可视化列表。我们以一个值为 1、2、3、4、5 和 6 的列表为例:

 head                                   slow
  ↓                                      ↓ 
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│value: 1 │  │value: 2 │  │value: 3 │  │value: 4 │  │value: 5 │  │value: 6 │  
│next: —————→│next: —————→│next: —————→│next: —————→│next: —————→│next:None│
└─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘

执行head_second_half = reverse(slow)后,我们有这种情况:

 head                                   slow                   head_second_half
  ↓                                      ↓                         ↓           
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│value: 1 │  │value: 2 │  │value: 3 │  │value: 4 │  │value: 5 │  │value: 6 │  
│next: —————→│next: —————→│next: —————→│next:None│←—————:next │←—————:next | 
└─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘

因此,如果现在您要迭代从 head 开始的列表,您将得到 1、2、3、4。从head 开始时,您无法再到达节点 5 和 6,因为 4 处的节点已成为尾节点,即它没有 next。显然它不能同时是下半场的尾巴,也是一个仍然连接到值为 5 的节点的节点。它只能处于一种状态。这就是它截断原始列表的方式。

通过第二次反转,您可以将列表恢复到其原始状态。

回想一下,在这个过程中只有这 6 个节点。不会创建或复制其他节点。只有这 6 个存在。唯一发生的事情是使用了几个变量来引用某些节点,并且一些节点获得了不同的next 值,但我们继续使用给定的 6 个节点。没有副本。

【讨论】:

  • 谢谢 我相信我现在明白了。我对此代码也有不同的问题,但由于它有点不同,我将发布一个新问题。
猜你喜欢
  • 2023-04-10
  • 2016-03-28
  • 2018-04-15
  • 1970-01-01
  • 1970-01-01
  • 2014-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多