Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 双链表哨兵法_Java_Linked List_Doubly Linked List - Fatal编程技术网

Java 双链表哨兵法

Java 双链表哨兵法,java,linked-list,doubly-linked-list,Java,Linked List,Doubly Linked List,我正在浏览Java中的双链接列表,我正在阅读来自Java的双链接列表中的哨兵。哪个国家 为了避免在附近操作时出现一些特殊情况 双链接列表的边界,它有助于在 列表的两端:列表开头的头节点,以及 列表末尾的拖车节点。这些“虚拟”节点是已知的 作为哨兵(或卫兵),他们不存储 一级序列 那些特殊情况是什么?为什么我们需要哨兵方法?是强制性的吗?如果我们对双链表使用正常的方法(没有哨兵),这不会节省这些额外节点的内存吗?当以循环方式制作双链表时,我们必须移除哨兵吗 维基百科注释简要提到使用sentinel

我正在浏览Java中的双链接列表,我正在阅读来自Java的双链接列表中的哨兵。哪个国家

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


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

维基百科注释简要提到使用sentinel节点简化链表的实现

sentinel节点是位于列表前面的虚拟节点

在双链接列表中,sentinel节点指向列表的第一个和最后一个元素。我们不再需要像处理单链接列表那样,为列表的开头和结尾保留单独的指针

我们也不必担心头指针和尾指针的更新,因为正如我们将看到的,如果我们在sentinel节点之后插入,从而在列表中预先插入一个项,或者在sentinel节点之前插入,从而在列表中追加一个项,那么这种情况就会自动发生

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

但是,数据结构通常使用容器对象进行设计,容器对象调解数据结构用户与数据结构实现之间的通信,因此我们将保留容器对象

@6502 on的回答非常有用

以下是双链接节点列表中删除节点的代码,其中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;


正如您所看到的,对于双链接列表,所有特殊情况和所有条件都删除了虚拟节点方法。

维基百科注释简要提到使用sentinel节点简化链接列表的实现

sentinel节点是位于列表前面的虚拟节点

在双链接列表中,sentinel节点指向列表的第一个和最后一个元素。我们不再需要像处理单链接列表那样,为列表的开头和结尾保留单独的指针

我们也不必担心头指针和尾指针的更新,因为正如我们将看到的,如果我们在sentinel节点之后插入,从而在列表中预先插入一个项,或者在sentinel节点之前插入,从而在列表中追加一个项,那么这种情况就会自动发生

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

但是,数据结构通常使用容器对象进行设计,容器对象调解数据结构用户与数据结构实现之间的通信,因此我们将保留容器对象

@6502 on的回答非常有用

以下是双链接节点列表中删除节点的代码,其中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;


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

这个答案对您有帮助吗?是否必须使用带有双链表的sentinels节点?否。这只是存储第一个和最后一个节点的技巧。它有助于编写更简洁的代码。您可以使用o(1)操作轻松地在第一个和最后一个位置插入节点。@SSP时间复杂度与(o(1))相同,无论是否使用伪/哨兵头/尾。拥有它们的唯一好处是简化插入/删除代码。你最后一次对O(1)的评论可能会让人感到困惑。这个答案对你有帮助吗?是否必须使用带有双链接列表的sentinels节点?没有。这只是存储第一个和最后一个节点的技巧。它有助于编写更简洁的代码。您可以使用o(1)操作轻松地在第一个和最后一个位置插入节点。@SSP时间复杂度与(o(1))相同,无论是否使用伪/哨兵头/尾。拥有它们的唯一好处是简化插入/删除代码。你最后一次对O(1)的评论可能会让人们感到困惑,以为你不是这样想的。