在java中,您可以使用LinkedList实现的堆栈。换句话说,您可以使用linkedlist来实现堆栈的所有功能。从这个意义上说,为什么我们仍然需要堆栈类,为什么我们不坚持使用链表来保持简单性呢? 感谢
答案 0 :(得分:6)
首先,在Stack
的文档介绍中,它说:
Deque
接口及其实现提供了一套更完整,更一致的LIFO堆栈操作,应优先使用该类。
这告诉我们Stack
类主要是剩余的,使用较新的 Java Collections Framework 或多或少地变得多余。
其次,“提供相同的功能”并不是衡量一个班级是否存在的好方法。虽然LinkedList
提供了堆栈所需的所有操作,但它的性能很差。链接列表适用于在随机位置插入和删除元素。在堆栈中,我们只会附加到末尾或从末尾移除,这使得ArrayList
更有吸引力来实现堆栈。
此时,我们意识到ArrayList
和LinkdList
都提供了List
的功能,这使我们接近良好的面向对象设计的核心:
List
)。ArrayList
或LinkedList
)。 Stack
,只需委派到ArrayList
,但提供一个明确在其名称中说明其含义的类型和不提供可能违反堆栈概念的操作(如随机访问)。 (这不是java.util.Stack
让我们回到文档引用的内容。)请注意,List
与较新的Deque
界面之间的继承关系比List
和Stack
之间的继承关系更为一致。 LinkedList
实施Deque
这是正确的,因为Deque
要求可以添加元素或从开头或结尾删除元素,LinkedList
通过提供插入和删除来限定随机位置。另一方面,Stack
实现了List
,这应该被认为是有问题的。
延迟更新:因为我对“链接列表有利于在随机位置插入和删除元素的语句进行了投票。在堆栈中,我们只会附加到末尾或从末尾移除,这使得ArrayList
更有吸引力来实现堆栈。“,我想扩展它。
链接列表允许在恒定时间内在任意位置插入和删除元素。另一方面,给定其索引需要线性时间来查找元素。当我说它们适合在随机位置插入和删除时,我的意思是迭代器给出的位置,而不是索引。如果给出索引,插入和删除将是链接列表和数组的线性时间操作,但链接列表的常量因子将多更高。
基于数组的列表允许在结束时进行分摊的常量时间插入和删除,以及通过索引进行常量时间访问。在随机位置添加和删除元素是线性时间操作,无论位置是由索引还是由迭代器给出(基本上只是数组的索引)。
在堆栈实现中,链接列表的唯一优势 - 它不需要在常量时间内在任意位置插入和删除元素(由迭代器给出)。另一方面,它的内存开销相当高,并且其内存访问远远低于连续数组的内存访问。鉴于在任何一种情况下,从列表末尾追加和删除项目的渐近复杂度都是不变的,因此基于数组的列表是实现堆栈存储的更好选择。
更好的数据结构是可变数量的固定大小的缓冲区,通过指针链接在一起。这种数据结构通常用于实现所谓的双端队列。它提供了数组的大多数优点,只需要很少的额外开销,并且在末尾(或开头)添加和删除不仅是一个摊销,而且总是一个恒定时间的操作。
答案 1 :(得分:1)
Stack
类扩展Vector
,因此它已同步。 LinkedList
类不是。最佳选择取决于您尝试做什么和约束,但一般来说,同步类的开销会有所增加。另外,正如@NESPowerGlove所提到的,Deque
及其实现优先于Stack
答案 2 :(得分:0)
当您可以使用范围更窄或更正确的数据结构时,使用一种数据结构是有问题的,原因有两个:
更适合的数据结构可能针对其拥有的操作子集或特定操作进行了更优化(例如,假设您的应用程序需要List,并且它主要只是在列表中间插入数据通常,您可能需要考虑LinkedList与ArrayList相同的操作,但LinkedList更适合,因为insert(n)操作优于其他操作/功能)。
未来的代码读者会对为什么使用较不适合的数据结构感到困惑,因为它是代码气味。读者将花费更多时间阅读您的代码,甚至可以替换它,即使当切换到更适合的数据结构时,当前使用的操作不再优化。
另外,Java中更现代的堆栈实现是java.util.Deque。