简体   繁体   English

Python:如何在O(1)时间内删除单链接列表中的ONLY节点

[英]Python: How to delete ONLY node in a singly-linked list in O(1) time

I have read the posts below but they do not answer my issue. 我已经阅读了以下帖子,但他们没有回答我的问题。

Post 1 发布1

Post 2 发布2

Post 3 发布3

This post comes close to explaining. 这篇文章接近解释。 The top voted answer by @Rishikesh Raje, says that deleting the last node in a singly-linked list is @Rishikesh Raje投票最多的回答是,删除单链接列表中的最后一个节点是

[...] is generally not possible. [...]通常是不可能的。

Why is it generally not possible and not just "it's impossible"? 为什么通常不可能,而不仅仅是“不可能”? My questions is both in the theory itself and how that applies to Python? 我的问题既涉及理论本身,又适用于Python? The question was meant for C. 这个问题是给C的。

Moreover, my other question is for the case where the linked list only has one node which also makes it the last node. 此外,我的另一个问题是链表只有一个节点的情况,这也使其成为最后一个节点。

Background: I am solving this problem on LeetCode. 背景:我正在LeetCode上解决此问题 Although it doesn't ask for the case of deleting the last case, I tried it but can't seem to get it because of some feature I can't pinpoint. 尽管它不要求删除最后一种情况,但我尝试过,但由于某些我无法查明的功能而似乎无法获得。 Some direction here would be much appreciated. 这里的一些方向将不胜感激。 I added a method to print values for debugging. 我添加了一种打印值以进行调试的方法。

Here's the question: 这是问题:

Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. 编写一个函数以删除单链接列表中的节点(尾部除外),仅授予对该节点的访问权限。

Supposed the linked list is 1 -> 2 -> 3 -> 4 and you are given the third node with value 3, the linked list should become 1 -> 2 -> 4 after calling your function. 假设链表为1-> 2-> 3-> 4,并且给您第三个节点的值为3,则在调用函数后链表应变为1-> 2-> 4。

My code can achieve the required result 1 -> 2 -> 4: 我的代码可以达到所需的结果1-> 2-> 4:

# Definition for singly-linked list.
class ListNode(object):
  def __init__(self, x):
    self.val = x
    self.next = None

class Solution(object):
  def deleteNode(self, node):
    """
    :type node: ListNode
    :rtype: void Do not return anything, modify node in-place instead.
    """
    nextNode = node.next

    if nextNode:
      node.val = nextNode.val
      node.next = nextNode.next
    else:
      node = None

  def listToString(self, head):
    string = ""
    while head:
      string += str(head.val) + "\n"
      head = head.next

    return string


head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)

solution = Solution()
print(solution.listToString(head))
print('-'*10)
node = head.next.next
solution.deleteNode(node)
print(solution.listToString(head)) 

Running this gives me: 运行这个给我:

1
2
3
4

----------
1
2
4

But when I change the bottom to: 但是当我将底部更改为:

head = ListNode(1)

solution = Solution()
print(solution.listToString(head))
print('-'*10)
node = head
solution.deleteNode(head)
print(solution.listToString(head))

I get 我懂了

1

----------
1

The questions are: Why isn't 1 printed and not None ? 问题是:为什么不打印1而不打印None Mind you, this linked list has only one node (which means it is the last node) and that's what's passed to the function. 请注意,此链接列表只有一个节点(这意味着它是最后一个节点),这就是传递给函数的内容。 Can it be done? 能做到吗 If so, what are the modifications I should make? 如果是这样,我应该做哪些修改?

A function that takes a reference to the head node of a list can delete any element after the head, but there's no way for it to delete the head. 引用列表的头节点的函数可以删除头之后的任何元素,但是无法删除头。

If you think about it, this should be obvious. 如果您考虑一下,这应该很明显。 No matter what you do, your caller still has the same reference to the head that he passed in. 无论您做什么,呼叫者仍然会参考传入的标头。

But that's not a limitation of linked lists per se, it's just a limitation of your API. 但这本身并不是对链表的限制,而仅仅是对API的限制。 With a different API, it's not impossible at all: 使用不同的API,这根本不是不可能的:


A function that takes a reference to a "list handle" object that holds a reference to the head node can delete the head node like this: 引用对拥有头节点的引用的“列表句柄”对象进行引用的函数可以删除头节点,如下所示:

handle.head = handle.head.next

A function that takes a reference to a reference to the head node, like a C Node ** , can't be written directly in Python, but in languages where it can, it's just as easy as with a list handle: 引用头节点的引用的函数(例如C Node ** )不能直接用Python编写,但是在可以的语言中,就像使用列表句柄一样容易:

*head = (*head)->next

A list handle can really be as simple as: 列表句柄实际上可以很简单:

class LinkedList:
    def __init__(self, head=None):
        self.head = head

But usually you'd want to actually use it for something—eg, add insert , delete , append , etc. methods to it, maybe even store the length. 但是通常您实际上希望将其用于某些用途,例如,向其添加insertdeleteappend等方法,甚至可以存储长度。 (However, notice that this design can break tail sharing, where two different lists have different heads but the same tails, because now you can change part of a list through one LinkedList handle without the other one knowing you've done so.) (但是,请注意,这种设计可能会破坏尾部共享,因为两个不同的列表具有不同的头部但尾部相同,因为现在您可以通过一个LinkedList句柄更改列表的一部分,而另一个则不知道这样做了。)


Or, a function that takes a reference to the head node and returns the new head can also remove the head: 或者,引用头节点并返回新头的函数也可以删除头:

return head.next

Let's work this one out in a bit more detail: 让我们更详细地解决这个问题:

def deleteNode(head, node):
    if head == node:
        return None
    ptr = head
    while ptr and ptr.next != node:
        ptr = ptr.next
    if ptr.next == node:
        ptr.next = node.next
    return head

Needs a bit of error handling, but if you follow the rules it works: 需要一些错误处理,但是如果遵循规则,它将起作用:

head = ListNode(1)
head.next = ListNode(2)
head.next.next = ListNode(3)
head.next.next.next = ListNode(4)

# This goes from 1->2->3->4 to 1->2->4
head = deleteNode(head, head.next.next)

# And this goes to 2->4
head = deleteNode(head, head)

And obviously if you change this to search for a value instead of for a node, the same thing works. 而且很显然,如果将其更改为搜索值而不是节点,则同样的事情起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM