【问题标题】:Sentinel approach with Doubly Linked List使用双向链表的哨兵方法
【发布时间】:2020-01-22 18:12:26
【问题描述】:

我正在浏览 Java 中的双向链表,我正在阅读来自 Book 的双向链表中的哨兵。其中指出

为了避免在附近操作时出现一些特殊情况 双向链表的边界,它有助于在 列表的两端:列表开头的头节点,以及 列表末尾的尾部节点。这些“虚拟”节点是已知的 作为哨兵(或守卫),它们不存储 一级序列

那些特殊情况是什么?为什么我们需要哨兵方法?是强制性的吗?如果我们对双向链表使用正常的方法(没有哨兵)不会节省这些额外节点的内存吗?当以这种方式使用循环方法制作双链表时,我们必须删除哨兵吗?

【问题讨论】:

    标签: java linked-list doubly-linked-list


    【解决方案1】:

    维基百科的注释简要提到了使用哨兵节点来简化链表的实现。

    哨兵节点是位于列表前面的虚拟节点。

    在双向链表中,哨兵节点指向列表的第一个和最后一个元素。我们不再需要为列表的头部和尾部保留单独的指针,就像我们对单链表所做的那样。

    我们也不必担心更新头和尾指针,因为正如我们将看到的,如果我们在哨兵节点之后插入,这会自动发生,因此将项目添加到列表中,或者在哨兵节点之前插入,因此将一个项目附加到列表中。

    我们可以消除用于单链表的容器对象,因为哨兵节点可以跟踪列表中的第一个和最后一个元素。如果我们这样做了,那么我们将返回一个指向哨兵节点的指针给用户。

    但是,数据结构一般设计有一个容器对象,该容器对象介导数据结构的用户和数据结构的实现之间的通信,所以我们会保留容器对象。

    @6502 在How does a sentinel node offer benefits over NULL? 上的回答非常有帮助。

    以下是在节点的双向链表中删除节点的代码,其中NULL用于标记链表的结束,两个指针first和last用于保存第一个和最后一个节点的地址:

    // Using NULL and pointers for first and last
    if (n->prev) n->prev->next = n->next;
            else first = n->next;
    if (n->next) n->next->prev = n->prev;
            else last = n->prev;
    

    这是相同的代码,其中有一个特殊的虚拟节点来标记列表的结尾,列表中第一个节点的地址存储在特殊节点的下一个字段中,最后一个节点在哪里该列表存储在特殊虚拟节点的 prev 字段中:

    // Using the dummy node
    n->prev->next = n->next;
    n->next->prev = n->prev;
    

    节点插入也有同样的简化;例如,在节点 x 之前插入节点 n(具有 x == NULL 或 x == &dummy 表示在最后一个位置插入),代码将是:

    // Using NULL and pointers for first and last
    
    n->next = x;
    n->prev = x ? x->prev : last;
    if (n->prev) n->prev->next = n;
            else first = n;
    if (n->next) n->next->prev = n;
            else last = n;
    

    // Using the dummy node
    n->next = x;
    n->prev = x->prev;
    n->next->prev = n;
    n->prev->next = n;
    

    如您所见,为双向链表删除了所有特殊情况和所有条件的虚拟节点方法。

    【讨论】:

    • 这个答案对你有帮助吗?
    • 双链表必须使用哨兵节点吗?
    • 没有。它只是存储第一个和最后一个节点的技巧。它有助于编写更简洁的代码。并且您可以使用 o(1) 操作轻松地在第一个和最后一个位置插入节点。
    • @SSP 时间复杂度是相同的 (O(1)) 有或没有虚拟/哨兵头/尾。拥有它们的唯一好处是简化插入/删除代码。您对 O(1) 的最后评论可能会让人们产生其他想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-22
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    • 1970-01-01
    相关资源
    最近更新 更多