您可能是指一个双向链表,其中一个指针向前,另一个指针向后。这使您可以访问给定节点的下一个和上一个节点,而无需记住最后遇到的一个或两个节点(如在单链表中)。
但我发现让代码更加更加优雅的一件事是在列表中始终有两个虚拟元素,第一个和最后一个。这消除了插入和删除的边缘情况,因为您总是作用于列表中间的节点。
例如,创建一个空列表:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
显然,遍历列表略有修改(仅显示正向版本):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
插入要简单得多,因为您不必关心是在列表的开头还是结尾插入。在当前点之前插入:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
删除也更简单,避免了边缘情况:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
所有的代码都非常简洁,而且每个列表只需维护两个额外的节点,这在当今巨大的内存空间环境中并不是一个很大的负担。
警告 1:如果您在空间仍然很重要的情况下进行嵌入式编程,那么这可能不是一个可行的解决方案(尽管现在一些嵌入式环境也很糟糕)。
警告 2:如果您使用的语言已经提供了链表功能,那么最好这样做而不是自己动手(除非在非常特殊的情况下)。