数据结构与算法——栈(hello算法学习笔记)

武汉大学导航工程专业本科生,暑假自学Git-hub上的开源项目《hello算法》,该开源项目的地址为https://www.hello-algo.com/

今天要讲的是数据结构中的栈。

一、什么是栈?

栈(stack)是一种遵循先入后出逻辑的线性数据结构。我们可以把栈看出是一个羽毛球桶,往里装羽毛球的过程是入栈,取羽毛球的过程是出栈,先进的羽毛球后出,后进的先出。

我们把堆叠元素的顶部称为“栈顶”,底部称为“栈底”。将把元素添加到栈顶的操作叫作“入 栈”,删除栈顶元素的操作叫作“出栈”。

二、栈的常用操作:

方法      描述                                时间复杂度

push()   元素入栈(添加至栈顶) 𝑂(1)

pop()     栈顶元素出栈                  𝑂(1)

peek()   访问栈顶元素                  𝑂(1)

python里面的list类可以直接使用上面的方法

stack: list[int] = []
# 元素入栈
stack.append(1)
stack.append(3)
stack.append(2)
stack.append(5)
stack.append(4)
# 访问栈顶元素
peek: int = stack[-1]
# 元素出栈
pop: int = stack.pop()
# 获取栈的长度
size: int = len(stack)
# 判断是否为空
is_empty: bool = len(stack) == 0

三、栈的实现

1.基于链表的实现

使用链表实现栈时,我们可以将链表的头节点视为栈顶,尾节点视为栈底

class ListNode:
    def __init__(self,val:int):
        self.val:int=val#节点值
        self.next:ListNode|None=None#指向下一节点的引用
class LinkedListStack:
    def __init__(self):
        self._peek:ListNode|None=None
        self._size:int=0
    def size(self)->int:
        return self._size
    def is_empty(self)->bool:
        return self._size==0
    def push(self,val:int):#添加新元素的函数
        node=ListNode(val)#入栈的节点
        node.next=self._peek#新节点指向原来的栈顶元素
        self._peek=node#新的栈顶元素
        self._size+=1#栈的大小加1
    def pop(self)->int:#栈顶元素出栈的函数
        num=self.peek()
        self._peek=self._peek.next
        self._size-=1
        return num
    def peek(self)->int:#访问栈顶元素的函数
        if self.is_empty():
            raise IndexError("栈为空")
        return self._peek.val
    def to_list(self)->list[int]:
        arr=[]
        node=self._peek
        while node:
            arr.append(node.val)
            node=node.next
        arr.reverse()#反转列表
        return arr

2.基于数组的实现

class ArrayStack:
    def __init__(self):
        self._stack:list[int]=[]
    def size(self)->int:
        return len(self._stack)

    def is_empty(self)->bool:
        return self.size()==0

    def push(self,val:int):
        self._stack.append(val)#入栈

    def pop(self)->int:
        if self.is_empty():
            raise IndexError("栈为空")
        return self._stack.pop()#出栈

    def peek(self)->int:
        if self.is_empty():
            raise IndexError("栈为空")
        return self._stack[-1]#访问栈顶元素

    def to_list(self)->list[int]:
        return self._stack#返回列表用于打印


A=ArrayStack()#定义一个类对象
A.push(1)
A.push(2)
arr=A.to_list()
print(arr)
#两种实现对比
#时间效率:
#‧ 基于数组实现的栈在触发扩容时效率会降低,但由于扩容是低频操作,因此平均效率更高。
#‧ 基于链表实现的栈可以提供更加稳定的效率表现。
#空间效率:
#基于数组实现的栈可能造成一定的空间浪费。然而,由于链表节点需要额外存储指针,因此链表节点占用的空间相对较大。

四、每日一题

题目来源于leetcode,网址如下:1021. 删除最外层的括号 - 力扣(LeetCode)

有效括号字符串为空 """(" + A + ")" 或 A + B ,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。

  • 例如,"""()""(())()" 和 "(()(()))" 都是有效的括号字符串。

如果有效字符串 s 非空,且不存在将其拆分为 s = A + B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。

给出一个非空有效字符串 s,考虑将其进行原语化分解,使得:s = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。

对 s 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 s 。

示例 1:

输入:s = "(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。

示例 2:

输入:s = "(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。

示例 3:

输入:s = "()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""。

提示:

  • 1 <= s.length <= 105
  • s[i] 为 '(' 或 ')'
  • s 是一个有效括号字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

两眼一睁就是学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值