【问题标题】:Java - LinkedList push() pop() implies it is a stack, not a queue?Java - LinkedList push() pop() 暗示它是一个堆栈,而不是一个队列?
【发布时间】:2017-01-26 02:29:39
【问题描述】:

在我的数据结构课程中,我了解到LinkedList 是一个队列。就像现实生活中的排队一样,第一个进入队列的人将是第一个离开的人。说得通。如下所示,ListedList 实现了具有 FIFO(先进先出)过程的 Queue

但是,如果您查看方法 push(E)pop() 的描述,它们的内容如下:

推(E)

将一个元素压入此列表表示的堆栈。换句话说,在这个列表的前面插入元素。

pop()

从这个列表表示的堆栈中弹出一个元素。换句话说,删除并返回此列表的第一个元素。

那是....不是队列。那是一个堆栈。通过push 进入LinkedList 的第一个元素不能被pop 访问,直到它被pop()'ed 之后添加的每个元素。

这是为什么?我知道 LinkedLists 既可以用作堆栈(如果您只使用addFirst(E)removeFirst()),也可以用作队列(如果您只使用addFirst(E)removeLast() 或反之亦然)那为什么像这样?我觉得pop() 应该删除并返回最后一个元素,或者push(E) 应该在LinkedList 的末尾添加元素。那么它会更有意义。

TLDR:为什么LinkedListpushpop 暗示它作为堆栈工作,而LinkedList 实际上实现了Queue

【问题讨论】:

  • 列表本质上既不是堆栈也不是队列,但它可以用作任何一个。

标签: java data-structures linked-list queue


【解决方案1】:

Push()pop() 按照惯例是与Stacks 相关的操作(Deque,更具体地说,在此上下文中),这就是为什么您应该期望您的LinkedList 在使用这些方法时以这种方式工作。 如果您希望您的LinkedList 作为Queue 工作(它实现了Queue 接口),那么您想要使用的方法(如文档中所述)是add()remove()

See LinkedList Documentation

【讨论】:

    【解决方案2】:

    您提到的方法(push()pop())来自Deque 接口,该接口也由LinkedList 实现。 Deque 的 Javadoc 声明:

    支持两端元素插入和移除的线性集合。名称 deque 是“双端队列”的缩写,通常发音为“deck”。大多数 Deque 实现对其可能包含的元素数量没有固定限制,但此接口支持容量受限的双端队列以及没有固定大小限制的双端队列。

    换句话说,它与常规队列不同。

    如果你真的想使用LinkedList作为一个队列,你应该将变量分配给那个接口:

    Queue<String> queue = new LinkedList<>();
    

    这样做,您只能将queue 用作队列。该接口定义了add()remove() 等方法,用于在队列中添加和删除元素。

    【讨论】:

    • 哦,我忘了你可以做到Interf x = new ClassWhoImplementsInterf();。当您执行Apple x = new SuperApple(); 时会发生什么? (假设SuperAppleApple 的子类)在这种情况下你能不能只使用Apple 的方法,或者这个技巧只适用于接口?
    • 它基本上与类的工作方式相同,无论是抽象的还是具体的。虽然这将是一个完全不同的讨论,如果您想进一步解释,可能应该作为一个不同的问题提出。
    【解决方案3】:

    从类图中可以看出,LinkedList 既是List,又是Deque

    Deque 接口定义了一个“双端队列”抽象,可以同时充当 FIFO(即堆栈)或 LIFO(即Queue)...。来自javadocs

    双端队列也可以用作 LIFO(后进先出)堆栈。应优先使用此接口而不是旧的 Stack 类。当双端队列用作堆栈时,从双端队列的开头推送和弹出元素。

    pushpop 操作来自 Deque API 的 FIFO 端。


    LinkedList - push(), pop() 暗示它是一个堆栈,而不是一个队列?

    从逻辑上讲,这是不正确的。

    • push()pop() 暗示堆栈是正确的。
    • 但是,只有add()remove() 缺席 表示不是队列。

    FIFO 和 LIFO 功能并不相互排斥。

    【讨论】:

      【解决方案4】:

      LinkedList 是一个双端队列 (Deque),因此您可以从两端添加和删除元素。它还实现了List,它也允许你修改中间的部分。

      这并没有改变可以通过使用add/offerpoll /remove 将其用作队列的事实。

      【讨论】:

      • poppush 术语是否专门用于堆栈?我不想将我的数据结构的一个方法命名为 pop,然后突然意识到约定规定 pop 应该是一个删除第一个元素或其他内容的方法。
      • @Hatefiend AFAIK push/pop 仅用于堆栈(或类似堆栈的行为)。
      【解决方案5】:

      单链表是一个很好的堆栈,但只是一个非常糟糕的队列。只有双链双根列表才适合作为队列。

      单链表只允许在头部进行 O(1) 的插入和删除(即堆栈操作)。

      找到尾元素需要遍历 O(n) 中的所有列表(除非它是双根的)。移除尾部需要您修改倒数第二个元素。为了提高效率,您需要一个双链表(双根不足以使 O(1))

      当然,任何双链表都继承了单链表的堆栈功能。您仍然可以在 O(1) 中访问头部。所以队列堆栈并不矛盾。

      请注意,在 Java 现实中,由于开销的原因,LinkedList 几乎总是一个坏主意。对于堆栈和队列都不应该使用它,但您应该始终更喜欢基于数组的实现,除非您也经常在大型列表的 middle 中插入或删除对象。 (真的,基准测试LinkedList - 它非常慢且内存昂贵)。

      【讨论】:

        猜你喜欢
        • 2018-07-05
        • 2023-03-04
        • 2010-09-30
        • 2021-11-08
        • 1970-01-01
        • 2011-12-01
        • 2021-12-21
        • 2016-08-16
        • 2021-09-06
        相关资源
        最近更新 更多