有时候应该用LinkedList代替Stack

本文通过一道LeetCode题目,探讨了使用Stack与LinkedList作为栈时的性能差异,并解释了背后的原因。通过对两种数据结构特点的分析,得出在涉及频繁插入删除操作时,LinkedList实现栈能获得更高的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在LeetCode上刷题,刷到一道,题目是这样的:

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
        左括号必须用相同类型的右括号闭合。
        左括号必须以正确的顺序闭合。
        注意空字符串可被认为是有效字符串。

结果示例:

示例一:
        输入: “()”
        输出: true

示例二:
        输入: “()[]{}”
        输出: true

示例三:
        输入: “([)]”
        输出: false

使用了自己写的代码:

public static boolean isValid(String s){
        Stack<Character> stack = new Stack<>();
        for (char ch: s.toCharArray()){
            if (ch == '['){
                stack.push(']');
            }
            else if (ch == '('){
                stack.push(')');
            }
            else if (ch == '{') {
                stack.push('}');
            }
            else if(stack.isEmpty()||ch!=stack.pop()){
                return false;
            }
        }
        return stack.isEmpty();
    }

        也能够符合题目的要求,但是当查看别人的解法的时候,流程的代码基本一致,但是用的是LinkedList,而且描述的效率比我的高,于是我跑了一下进行对比:
在这里插入图片描述
        这时候就有疑惑了,为什么效率会差这么多?
        最后在网上找到了答案:
        Stack 继承自 Vector,而Vector 是矢量队列,和ArrayList一样,它也是一个动态数组,由数组实现 。但是ArrayList是非线程安全的,而Vector是线程安全的。
在这里插入图片描述

        而对于LinkedList,我们知道它是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
        看到这里,就能够理解为什么效率会低了。Stack 基于数组实现,LinkedList基于链表实现,数组随机访问效率高,但随机插入、随机删除效率低,链表与之相反。
        那么对于这道题,要进行一些插入和删除操作,那么我们利用LinkedList实现栈自然比Stack快很多了,效率也提高不少。
        最后总结一下:

        Stack:基于数组实现,随机访问(查找)效率更高,增删改效率较低
        LinkedList:基于链表实现,增删改效率更高,随机访问(查找)效率较低

        这道题也给了我启发,当我们追求时间效率的时候,如果有大量插入删除操作,不妨利用 LinkedList 实现栈的相关功能,而不是思维定式般地想到栈就用Stack。

        有时候寻找另一种方式去代替原有固定思想的事物,有时候会发现能实现同样的功能,但是带来的效果会更好。

<think>嗯,用户现在想了解LinkedList链表)和Stack)的比较,特别是关于后进先出(LIFO)的特性。首先,我需要确认用户的基本需求。用户可能在学习数据结构,或者在实际编程中遇到了相关问题,需要理解这两种结构的区别和适用场景。 首先,回顾LinkedListStack的基本概念。LinkedList是一种线性数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针。而Stack是一种抽象数据类型,遵循LIFO原则,只能在顶进行插入和删除操作。 接下来,比较两者的操作方式。LinkedList支持在任意位置插入和删除节点,而Stack的操作受限,只能在顶进行Push和Pop。这时候需要考虑用户是否理解这两种结构在操作上的限制和灵活性差异。 然后,分析实现方式。Stack可以用数组或LinkedList来实现。如果用数组实现,可能会有固定大小的限制,而LinkedList实现的可以动态扩展。用户可能想知道为什么选择不同的实现方式,以及各自的优缺点。 应用场景方面,LinkedList常用于需要频繁插入删除的场景,比如实现队列或图结构。而Stack常用于函数调用、括号匹配、撤销操作等。用户可能想了解在实际开发中如何选择合适的数据结构。 还要注意用户提到的“后进先出比较”,这可能是指比较Stack的LIFO特性与LinkedList的不同。需要强调虽然Stack可以用LinkedList实现,但LinkedList本身并不遵循LIFO,除非特意限制操作方式。比如,如果只在链表的一端进行插入和删除,那这个链表的行为就和一样了。 另外,用户可能存在的误区是认为LinkedListStack是同一层次的概念,但实际上LinkedList是实现Stack的一种方式。需要明确两者的层次关系,避免混淆。 最后,是否需要提供代码示例或更具体的应用实例?用户之前的回答中没有代码,但如果有的话可能更有助于理解。不过根据之前的回复,可能更倾向于理论解释,所以保持结构清晰,分点比较会更合适。 总结,用户的需求是理解LinkedListStack在结构和LIFO特性上的异同,需要明确两者的定义、操作、实现方式和应用场景,并指出它们的联系与区别,帮助用户在实际问题中选择合适的数据结构。</think>以下是关于**LinkedList链表)**和**Stack)**的对比分析,重点围绕**后进先出(LIFO)**特性展开: --- ### 一、核心概念对比 | **特性** | **LinkedList** | **Stack** | |------------------|-----------------------------------------|-----------------------------------------| | **数据结构本质** | 线性结构,节点包含数据+指针 | 抽象数据类型(ADT),基于LIFO原则 | | **操作自由度** | 可在任意位置插入/删除 | 仅允许在顶进行`push`和`pop`操作 | | **底层实现** | 自身是独立的数据结构 | 可通过数组或LinkedList实现 | | **LIFO特性** | 不天然遵循,需通过操作限制模拟 | 天然遵循LIFO | --- ### 二、操作方式对比 #### 1. **LinkedList** - **插入**:可在头、尾或中间插入节点,例如: ```java list.addFirst(item); // 头部插入(类似的push) list.add(index, item); // 任意位置插入 ``` - **删除**:可删除任意节点,例如: ```java list.removeFirst(); // 头部删除(类似的pop) list.remove(index); // 任意位置删除 ``` #### 2. **Stack** - **插入**:仅限顶`push`操作: ```java stack.push(item); // 将item压入顶 ``` - **删除**:仅限顶`pop`操作: ```java item = stack.pop(); // 移除并返回顶元素 ``` --- ### 三、LIFO特性实现差异 #### 1. **LinkedList如何模拟的LIFO?** - **限制操作**:若仅通过`addFirst()`和`removeFirst()`操作链表头部,则行为等价于。 数学表达: 若链表为$L = [a_1, a_2, ..., a_n]$,操作后变为$L = [a_0, a_1, ..., a_n]$(压),或$L = [a_1, ..., a_n]$(弹)。 #### 2. **Stack的LIFO本质** - **强制约束**:的LIFO由设计原则保证,无论底层用数组还是链表实现,操作均被限制在顶。 例如,表达式求值中操作符的顺序严格遵循LIFO,如计算`$3 + (5 * 2)$`时,乘法优先于加法。 --- ### 四、应用场景对比 | **场景** | **LinkedList适用性** | **Stack适用性** | |------------------|----------------------------------------|-----------------------------------------| | **动态数据管理** | 频繁增删(如实现队列、图结构) | 无中间操作需求,仅需LIFO(如函数调用)| | **内存占用** | 每个节点需额外存储指针,空间开销较大 | 若用数组实现,内存连续,效率更高 | | **典型应用** | 浏览器历史记录(双向链表) | 括号匹配、撤销操作(操作历史) | --- ### 五、关键总结 1. **LinkedList更灵活**:可自由操作节点,但需手动约束才能实现LIFO。 2. **Stack更专注**:天然支持LIFO,适合受限操作场景,但底层依赖数组或链表实现。 3. **性能差异**: - 的`push/pop`时间复杂度为$O(1)$(无论数组或链表实现)。 - 链表的任意位置插入/删除时间复杂度为$O(1)$(已知节点位置时)或$O(n)$(需遍历查找)。 --- **如何选择?** - 若需严格LIFO且无需中间操作 → **Stack** - 若需动态增删或扩展功能(如双向操作) → **LinkedList**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是哈猿啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值