python中处理链表时特别注意引用传递的问题

在解决剑指offer第57题删除已排序链表中重复结点时,遇到因引用传递导致的错误。首先,用字典统计链表结点值的频率,再遍历链表,若结点值频率为1,则创建新结点加入新链表。错误1:只处理了首次出现的单个结点;错误2:未遍历完整个链表,因为复制结点时实际上引用了同一地址。解决方法需理解Python中可变对象的深浅拷贝概念。

刷题刷到剑指offer第57题(删除链表(已排序)中重复的结点)时,按照自己的思路做的,发现输出结果时出现过以下问题:

做题思路:链表相当于一个前后有关系的数组,于是先把此题当做删除数组中重复的元素来思考,立马想到可以借用python中的字典来统计每个数字出现的频数(这样遍历一次的时间复杂度为O(n)),然后在通过遍历数组,通过判断该数字是否只出现一次,如果只出现一次则把它放进新的数组中,这样就把数组中重复的元素删除了(空间复杂度为O(n))。因此这道题也借用这种思路做。

步骤:(1)遍历一次链表,统计每个结点的值出现的频数;

         (2)遍历一次链表,如果结点值的频数为1,那么创建一个新结点,并与已有结点相连(如果是头结点,则直接创建)。


遇到的问题:

(1)测试实例为{1,1,2,3,4,4,5,5},输出为{2,3,4,4,5,5}。错误原因:对于只出现一次的结点,采用直接复制,导致后面重复的结点没有做处理。




(2)测试实例为{1,1,2,3,4,4,5,6},输出为{2,3}。错误原因:由于第一个错误是没有对只出现一次的结点后面重复的结点做处理,于是就直接在只出现一次的结点后面直接加了一条语句,这导致步骤二还没有遍历完链表就直接退出了。出现这个错误的原因是在python中,对于可变对象,直接复制意味着两个变量引用指向同一个地址,只要内容改变,两个变量引用的值都发生变化。





注意:由于这道题链表是有序的,所以肯定有更简便的方法。假如这道题的链表是无序时,也可以按照这个思路做。

### 3.1 链表节点的引用机制与内存管理 在 Python 中,链表的结构通常由节点对象组成,每个节点包含数据域和指向下一个节点的指针。链表的非连续存储特性决定了其节点在内存中是分散存放的,而每个节点通过指针域连接下一个节点的地址。因此,在链表操作中返回的是节点的内存地址,而不是节点的具体值,这是为了实现对节点的引用和操作[^3]。 例如,在链表的构建过程中,每个新节点的 `next` 属性存储的是下一个节点的引用地址。这种设计允许链表在不复制整个结构的情况下进行高效插入、删除和遍历操作。如果每次操作都返回具体值,会导致大量数据复制,增加内存开销。 ### 3.2 返回地址的必要性与链表操作效率 链表的遍历、插入和删除操作通常依赖于节点地址的传递。例如,在查找某个值的节点位置,程序通过头节点开始,逐个访问每个节点的 `next` 指针,直到找到目标节点或遍历完整个链表。在该过程中,函数返回的是目标节点的地址,而不是其具体值,因为地址可以直接用于后续操作,如修改节点内容或调整链表结构[^1]。 以下是一个查找链表中某个值位置的示例: ```python def find_value(self, value): p = self.head index = 0 while p: if p.value == value: return index + 1 p = p.next index += 1 return -1 ``` 该函数通过 `p` 指针遍历链表,返回的是节点的位置,而不是节点地址。但在实际链表操作中,节点地址的传递更为直接和高效,尤其是在修改链表结构,如插入、删除节点等。 ### 3.3 链表结构的动态调整与引用传递链表的插入或删除操作中,需要修改节点之间的链接关系。例如,在删除重复节点,程序通过比较当前节点和下一个节点的值,若相同则修改当前节点的 `next` 属性为下下个节点的地址。这种操作依赖于节点地址的传递,而不是复制整个链表内容。通过操作内存地址,可以在不复制整个链表的情况下实现结构的动态调整[^2]。 以下是一个删除排序链表中重复节点的示例: ```python current = head while current and current.next: if current.val == current.next.val: current.next = current.next.next else: current = current.next ``` 该代码通过 `current` 指针访问链表节点,修改 `current.next` 的值为 `current.next.next` 的地址,从而跳过重复节点。这种操作方式避免了链表内容的复制,提高了操作效率。 ### 3.4 Python链表的中间节点查找与地址返回 在查找链表中间节点,通常采用双指针法或遍历计算长度的方式。例如,通过计算链表长度并再次遍历到中间位置,程序可以返回中间节点的地址,而不是具体值。这是因为中间节点的地址可以直接用于后续操作,如修改链表结构或访问其值域。 以下是一个查找中间节点的示例: ```python def middle_node_of_linked_list_by_iteration(head): length = 0 current = head while current: length += 1 current = current.next middle = length // 2 current = head for _ in range(middle): current = current.next return current ``` 该函数返回的是中间节点的引用地址,而不是其值。这种设计使得链表操作更加灵活,可以避免重复遍历和数据复制。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值