我正在从 T Cormen 的《算法导论》一书中学习链表。
书中有这样一段内容:
给定列表中的元素 x,x.next 指向其在链表中的后继元素,x.prev 指向其前趋元素。
如果 x.prev=NIL,则元素 x 没有前驱,因此是列表的第一个元素或头。如果 x.next=NIL,则元素 x 没有后继元素,因此是列表的最后一个元素或尾部元素。属性 L.head 指向列表的第一个元素。如果 L.head=NIL,则列表为空。
过程 LIST-DELETE 从链表 L 中删除一个元素 x。必须给它一个指向 x 的指针,然后它通过更新指针将 x 从链表中“拼接”出来。
LIST-DELETE(L,x)
1 if x.prev!= NIL
2 x.prev.next = x.next
3 else L.head = x.next
4 if x.next !=
NIL
5 x.next.prev = x.prev
但是,我没有得到文本中的任何部分。首先,他们检查 x 中包含的下一个可能的内存地址是否为 NIL。如果不是 NIL,则它们将 x.prev.next 替换为 x.next。现在,x.prev.next只是一个返回x.key的内存地址的函数,即返回x中的地址。这意味着 x.prev.next 和 x 是相同的。最后,语句 x.prev.next=x.next 看起来毫无意义且荒谬,因为 x.prev.next 不是变量,而是返回值的函数,并且将新值分配给“函数返回语句”是没有意义的。所以,我认为,他们试图暗示 x=x.next,因此 x 中的内存地址等于 x.key 之后下一个元素的内存地址。
接下来,他们检查 x.prev 是否等于 NIL,这意味着 x=L.head。在这种情况下,我们将 L.head 更改为 x.next,即使列表从 x.key 之后的元素开始。因此,x 中包含的内存地址中的元素被删除。
最后,他们似乎检查 x.next 是否等于 NIL。如果不是,则 x.next.prev(=x)=x.prev.
因此,存储在 x 中的内存地址被 x.prev 返回的内存地址替换。
但是我真的不知道删除 x 中包含的地址中的元素的实际工作是如何完成的。我对此一无所知。
我不知道那本书,但是删除喜欢列表中的元素的问题是你可能会破坏元素之间的链接(因为如果你删除 x 那么 x.prev 无法到达 x.next 并且列表现在在技术上分为两个列表)。
为了解决这个问题,我们需要将 x.prev 附加到 x.next,这样 x.prev.next 就等于 x.next,这样我们就可以安全地删除 x。
如果链表中有一个头或尾指向列表的开头和结尾,那么在删除这些元素时你应该注意。
如果要删除第一个元素(比如说x),那么你需要使 head 等于 x.next
但是如果要删除最后一个元素,则 tail 应等于 x.prev。