Why is deleting in a single linked list O(1)?

那年仲夏 提交于 2019-11-30 03:15:05

I am not sure I see in the Wikipedia article where it says that it's possible to remove the last entry of a singly-linked list in O(1) time, but that information is incorrect in most cases. Given any individual node in a linked list, it is always possible to remove the node after it in O(1) time by rewiring the list around that new node. Consequently, if you were given a pointer to the penultimate node in a linked list, then you could delete the last element of the list in O(1) time.

However, if you didn't have any extra pointers into the list other than a head pointer, then you could not delete the last element of the list without scanning to the end of the list, which would require Θ(n) time, as you have noted. You are absolutely correct that just deleting the last node without first changing the pointers into it would be a Very Bad Idea, since if you were to do this the existing list would contain a pointer to a deallocated object.

More generally - the cost to do an insertion or deletion in a singly-linked list is O(1), assuming you have a pointer to the node right before the one you want to insert or delete. However, you might have to do extra work (up to Θ(n)) to find that node.

Hope this helps!

The addition/deletion of ANY node at ANY location is O(1). Code just play with fixed cost (few pointers calculations and malloc/frees) to add/delete the node. This arithmetical cost is fixed for any specific case.

However, the cost to reach(Indexing) the desired node is O(n).

The article is merely listing the addition/deletion in multiple sub-categories(adding in middle, beginning, end) to show that cost for adding in middle differs than adding in beginning/end (But the respective costs are still fixed).

For example, you can have a pointer to the element before last ("second from end") and when deleting: 1. Delete *next of this "second from end" element. 2. Set this "second from end" *next to NULL

If you're including the cost of fixing the dangling node, you can still do it in O(1) with the use of sentinel node for the end (also described on that page).

Your "empty" list starts with a single sentinel

Head -> [Sentinel]

Add some stuff

Head -> 1 -> 2 -> 3 -> [Sentinel] 

Now delete the tail (3) by marking the node that was 3 as invalid, and then removing the link to the old sentinel, and freeing the memory for it:

Head -> 1 -> 2 -> 3 -> [Sentinel] 
Head -> 1 -> 2 -> [Sentinel] -> [Sentinel] 
Head -> 1 -> 2 -> [Sentinel]
user268396

O(1) simply means "constant cost". It does not mean 1 operation. It means "at most C" operations with C being fixed regardless of other parameters changing (such as list size). In fact, in the sometimes confusing world of big-Oh: O(1) == O(22).

By contrast deleting the whole list has O(n) cost, because the cost changes with the size (n) of the list.

For future reference, I must say after some research I found that none of the arguments provided in response to this question are relevant. The answer is that we simply decide for the top of the stack to be the head of the linked list (rather than the tail). This will introduce a slight change into the push routine but then the pop and push will both remain o(1).

If you are give a pointer to the node to be deleted in a single linked list, then you can delete this node in constant time by simply copying the next node onto the node to be deleted.

M pointer to node to delete
M.data=M.next.data
M.next=M.next.next

Otherwise, if you need to search for the node then you cannot do better than O(n)

Yes, you can do this in O(1) time even if you're not maintaining a pointer to the "previous element".

Let's say you have this list, where "head" and "tail" are static pointers, and "End" is a node marked as an end. You can use "next == NULL" as normal, but in this case you have to disregard the value:

head -> 1 -> 2 -> 3 -> 4 -> 5 -> End <- tail

Now, you're given a pointer to node 3, but not its previous node. you have the head and tail pointers too. Here's some python-ish code, assuming a SingleLinkedList class.

class SingleLinkedList:

    # ... other methods

    def del_node(self, node):  # We "trust" that we're only ever given nodes that are in this list.
        if node is self.head:
            # Simple case of deleting the start
            self.head = node.next
            # Free up 'node', which is automatic in python
        elif node.next is self.tail
            # Simple case of deleting the end. This node becomes the sentinel
            node.value = None
            node.next = None
            # Free up 'self.tail'
            self.tail = node
        else:
            # Other cases, we move the head's value here, and then act
            # as if we're deleting the head.
            node.value = self.head.value
            self.head = self.head.next
            new_head = self.head.next
            # Free up 'self.head'
            self.head = new_head

Alas, this reorders the list, and moves values around, which may or may not be okay for your application.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!