私が読んでいる多くの資料では、二重リンク リスト (DLL) 内の内部要素を削除するとO(1)
; と書かれていますが、なぜそうなるのでしょうか?
SLL 用である理由は理解していますO(n)
。リストを走査しO(n)
て削除しますO(1)
が、要素を見つけるには DLL 内のリストを走査する必要はないのでしょうか?
ベストアンサー1
二重リンクリストの場合、要素を削除するのに一定の時間がかかります。一度それがどこにあるかがわかれば。
単方向リンクリストの場合、要素がどこにあるかがわかれば、要素を削除するのにかかる時間は一定です。そしてその前身はです。
あなたが指しているリンクは、単方向リンクリストの削除を としてO(n)
、二重リンクリストの削除を として示しているのでO(1)
、削除したい要素がどこにあるかがすでにわかっている場合は となることは確かですが、ない他に何か。
その場合、二重リンク リストの場合は、prev
とnext
ポインターを使用してそれを削除し、 を得ることができますO(1)
。先頭または末尾にいるエッジ ケースを無視すると、次のようになります。
corpse->prev->next = corpse->next
corpse->next->prev = corpse->prev
free (corpse)
しかし、削除したいノードしか知らない単連結リストでは、corpse->prev
その前のノードを取得するために使用することはできません。はリンクはありませんprev
。
代わりに探す前の項目を削除するには、先頭からリストをトラバースして、next
削除する要素の を持つ項目を探します。これには が必要でO(n)
、その後、実際の削除のためにもう一度 が実行されますO(1)
(ここでも、簡単にするためにエッジ ケースは無視します)。
lefty = head
while lefty->next != corpse:
lefty = lefty-> next
lefty->next = corpse->next
free (corpse)
それはその記事ではなぜ 2 つの複雑さが異なるのか。
余談ですが、単方向リンクリストには削除を可能にする最適化がありますO(n)
(削除したい項目とその前の項目が見つかったら、削除は実質的に O(1) になります)。コードで言えば、次のようになります。
# Delete a node, returns true if found, otherwise false.
def deleteItem(key):
# Special cases (empty list and deleting head).
if head == null: return false
if head.data == key:
curr = head
head = head.next
free curr
return true
# Search non-head part of list (so prev always exists).
prev = head
curr = head.next
while curr != null:
if curr.data == key:
# Found it so delete (using prev).
prev.next = curr.next
free curr
return true
# Advance to next item.
prev = curr
curr = curr.next
# Not found, so fail.
return false