教科书错了。列表的第一个成员没有可用的“前一个”指针,因此如果它恰好是链中的第一个元素,则需要额外的代码来查找和取消链接(通常 30% 的元素是其链的头部,如果N=M,(当将 N 个项目映射到 M 个插槽时;每个插槽都有一个单独的链。)
编辑:
比使用反向链接更好的方法是使用 pointer 指向指向我们的链接(通常是 -> 列表中前一个节点的下一个链接)
struct node {
struct node **pppar;
struct node *nxt;
...
}
删除则变为:
*(p->pppar) = p->nxt;
这个方法的一个很好的特点是它同样适用于链上的第一个节点(其 pppar 指针指向某个指针,该指针不是节点的一部分。
2011 年 11 月 11 日更新
由于人们看不到我的观点,我将尝试说明。例如,有一个哈希表table(基本上是一个指针数组)
还有一堆节点one、two、three,其中一个必须删除。
struct node *table[123];
struct node *one, *two,*three;
/* Initial situation: the chain {one,two,three}
** is located at slot#31 of the array */
table[31] = one, one->next = two , two-next = three, three->next = NULL;
one->prev = NULL, two->prev = one, three->prev = two;
/* How to delete element one :*/
if (one->prev == NULL) {
table[31] = one->next;
}
else {
one->prev->next = one->next
}
if (one->next) {
one->next->prev = one->prev;
}
现在很明显,上面的代码是 O(1),但有一些讨厌的地方:它仍然需要 array 和索引 31,所以在 大多数情况下 是一个节点是“自包含的”,并且指向节点的指针足以将其从其链中删除,除了,当它恰好是其链中的第一个节点时;然后需要更多信息来查找table 和31。
接下来,考虑具有指向指针的等效结构作为反向链接。
struct node {
struct node *next;
struct node **ppp;
char payload[43];
};
struct node *table[123];
struct node *one, *two,*three;
/* Initial situation: the chain {one,two,three}
** is located at slot#31 of the array */
table[31] = one, one-next = two , two-next = three, three->next = NULL;
one->ppp = &table[31], two->ppp = &one->next, three->ppp = &two-next;
/* How to delete element one */
*(one->ppp) = one->next;
if (one->next) one->next->ppp = one->ppp;
注意:没有特殊情况,也不需要知道父表。 (考虑存在多个哈希表但具有相同节点类型的情况:删除操作仍需要知道应该从哪个表中删除节点)。
通常,在 {prev,next} 场景中,通过在双链表的开头添加一个虚拟节点来避免特殊情况;但这也需要分配和初始化。