首页 > 解决方案 > 更改链表中节点的数据不会更改引用同一内存地址的另一个变量的数据

问题描述

我不知道如何命名这篇文章。

main最初,一旦我尝试反转链接列表的后半部分,我的原始链接列表在我的函数中更改时遇到了麻烦,我相信我现在明白了。但是,我现在无法理解在处理链接列表中的数据时发生了什么。我写下了我的代码,但在接近尾声时我写了一个单独的函数来解释我对此的思考过程,并解释为什么我无法理解。

class Node:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next
    
def find_middle(head):
    slow, fast = head, head

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

    return slow

def reverse_second_half(head):
    middle = find_middle(head)
    second_half_reversed = reverse(middle, head)
    

    return '\nfinished'

def reverse(head, original_head):
    prev = None
    iteration = 1
    while head is not None:
        pointer = original_head

        print('\noriginal list iteration = ' + str(iteration) + '\n')
        while pointer is not None:
            print('current pointer value = ' + str(pointer.value))
            pointer = pointer.next

        iteration += 1

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

def main():
    head = Node(1)
    head.next = Node(2)
    head.next.next = Node(3)
    head.next.next.next = Node(4)
    head.next.next.next.next = Node(5)

    print(reverse_second_half(head))

main()

main我调用reverse_second_half哪些调用find_middlereverse函数。在我找到链接列表的中间部分后,我从我找到的中间节点开始反转链接列表的后半部分find_middle

我将其传递给反向,但我也将“原始列表”作为第二个参数传递。我这样做是因为我想看看一旦反转开始执行,原始列表是如何改变的。

我看到在第一次迭代中,但在任何反转发生之前,原始链表及其所有值都会被打印出来,从而在控制台中打印出以下内容。

original list iteration = 1

current pointer value = 1
current pointer value = 2
current pointer value = 3
current pointer value = 4
current pointer value = 5

对于第二次迭代...

original list iteration = 2

current pointer value = 1
current pointer value = 2
current pointer value = 3

依此类推......(每隔一次迭代打印出第二次迭代作为输出给出的内容)。

所以我知道我不是在操作列表的副本,而是在操作同一个列表本身。

根据我的理解,我们可以看到在任何反转发生之前的第一次迭代期间的原始链表是

原头 没有任何
值:1,下一个:-> 值:2,下一个:-> 值:3,下一个:-> 值:4,下一个:-> 值:5,下一个:-> 没有任何

然后一步一步完成第一次迭代

原头 下一个 没有任何
值:1,下一个:-> 值:2,下一个:-> 值:3,下一个:-> 值:4,下一个:-> 值:5,下一个:-> 没有任何
原头 没有任何
值:1,下一个:-> 值:2,下一个:-> 值:3,下一个:-> 没有任何

在这里,我看到原始列表已更改,不再包含后半部分。我可以在这里看到我没有某个列表的单独副本,但是我们正在使用同一个列表本身,因为我们只是将变量指向内存地址。这对我来说似乎很奇怪,因为当我这样做时

next = head.next

在第一次迭代期间,从上表中我们看到 next 指向值为 4 的节点,但是在下一行

head.next = prev

prev == None应该将列表更改为

1 -> 2 -> 3 -> None

但是如果next指向head.nexthead.next更改None为它是怎么回事

head = next

获取列表4 -> 5

这对我来说似乎不对我创建了一个函数来显示我的想法

def change_value_in_linked_list(head):
    middle = find_middle(head)

    middle.value = 'oops'

    while head is not None and head.next is not middle:
        head = head.next

    print(head.next.value)
    print(middle.value)

    return '\nfinished'

如果我们将上面的代码与其余代码一起运行并在 main 中调用此函数而不reverse_second_half只是出于测试目的而调用,我会看到head.next.valuemiddle.value在更改middle.value为 string后包含相同的数据oops。我的理解是中间点指向一个内存位置,当我们改变它的数据并试图通过遍历链表来找到相同的内存位置时,我们看到现在在原始链接列表中我们发现改变的数据

1 -> 2 -> 'oops' -> 4 -> 5

但是,如果我将函数改为 this

def change_value_in_linked_list(head):
    middle = find_middle(head)

    middle.value = 'oops'

    while head is not None and head.next is not middle:
        head = head.next

    head.next = None
    print(head.next)
    print(middle.value)

    return '\nfinished'

更改后,middle.value = 'oops'我假设head.next.valueandmiddle.value是“哎呀”,根据我们之前看到的情况,这是正确的。但是,我现在添加了

head.next = None

我再次假设 head.next 指向一个内存位置,我们正在将该数据更改为None. middle指向同一个内存位置,但是当打印出包含在head.nextmiddle中间的数据时,仍然包含一个具有值的有效节点,oops并且head.next现在是None

也许我错过了一些明显的东西,但这让我失望。就好像参数是在声明更改由不同指针引用的内存位置中的数据一样,将每个指针的数据更改为更改后的数据,因为这些指针没有被分配该数据,而是仅指向内存位置,但是通过这样做head.next = None并看到head.nextand middle(指向同一内存位置的两个指针)包含不同的数据与此论点相矛盾。

标签: pythonmemorylinked-listmemory-address

解决方案


如果我正确理解了您的问题,我认为您的困惑在于变量/引用如何绑定到使用=. 也许这些图形会有所帮助:

初始状态:

next = head.next

head.next = prev

prev = head

head = next

您的链接列表已被切断。


推荐阅读