编程基础 —— 栈

目录

1 栈简介

(1)定义

(2)基本操作

(3)线性表

(4)后进先出原则

2 栈的顺序存储与链式存储

3 栈的基本操作

4 栈的顺序存储

(1)基本描述

(2)栈的顺序存储代码

5 栈的链式存储

---->基本描述

 6 练习

(1)有效括号

(2)逆波兰表达式求值

1 栈简介

(1)定义

  • 栈(Stack):也称为堆栈;是一种线性表数据结构,是一种只允许在表的一端进行插入和删除操作的线性表。
  • 栈顶(Top):栈中允许插入和删除的一端。
  • 栈底(Bottom):除栈顶的另一端。
  • 空栈:表中没有任何元素。

(2)基本操作

  • 插入操作(又称入栈、进栈)
  • 删除操作(又称出栈、退栈)

(3)线性表

栈首先是一个线性表,栈中元素具有前驱后继的线性关系。

(4)后进先出原则

根据栈的定义,每次删除的总是堆栈中当前的栈顶元素,即最后进入堆栈的元素。而在进栈时,最先进入堆栈的元素一定在栈底,最后进入堆栈的元素一定在栈顶。

2 栈的顺序存储与链式存储

与线性表类似,栈有两种存储的表示方式,即顺序栈与链式栈。

  • 顺序栈

即堆栈的顺序存储结构,利用一组地址连续的存储单元依次存放自栈底到栈顶的元素,同时使用指针top指示栈顶元素在顺序栈中的位置。

  • 链式栈

即堆栈的链式存储结构,利用单链表的方式来实现堆栈,栈中元素按照插入顺序依次插入到链表的第一个节点之前,并使用栈顶指针top指示栈顶元素,top永远指向链表的头节点位置。

3 栈的基本操作

  • 初始化空栈:创建一个空栈,定义栈的大小size,以及栈顶元素指针top。
  • 判断栈是否为空:当堆栈为空时,返回True;当堆栈不为空时,返回False。一般只用于栈中删除操作与获取当前栈顶元素操作中。
  • 判断栈是否已满:当堆栈已满时,返回True;当堆栈未满时,返回False。一般只用于顺序栈中插入操作与获取当前栈顶元素操作中。
  • 插入元素(进栈、入栈):相当于在线性表最后元素后面插入一个新的数据元素。并改变栈顶指针top的指向位置。
  • 删除元素(出栈、退栈):相当于在线性表最后元素后面删除最后一个数据元素。并改变栈顶指针top的指向位置。
  • 获取栈顶元素:相当于获取线性表中最后一个数据元素。与插入元素、删除元素不同的是,该操作并不改变栈顶指针top的指向位置。

4 栈的顺序存储

栈最简单的实现方式就是借助于一个数组来描述堆栈的顺序结构。在Python中可以借助列表list来实现,这种采用顺序存储结构的堆栈也被称为顺序栈。

(1)基本描述

# self.top 指向栈顶元素所在位置

  • 初始化空栈:使用列表创建一个空栈,定义栈的大小self.size,并令栈顶元素指针self.top指向-1,即self.top==-1。
  • 判断栈是否为空:当self.top==-1时,说明堆栈为空,返回True,否则返回False。
  • 判断栈是否已满:当self.top==self.top-1,说明堆栈已满,返回True,否则返回False。
  • 获取栈顶元素:先判断堆栈是否为空,为空直接抛出异常。不为空则返回self.top指向的栈顶元素,即self.stack[self.top]。
  • 插入元素(进栈、入栈):先判断堆栈是否已满, 已满直接抛出异常。如果堆栈未满,则在self.stack末尾插入新的数据元素,并令self.top向右移动1位。
  • 删除元素(出栈、退栈):先判断堆栈是否为空,为空直接抛出异常。如果堆栈不为空,则先让self.top向左。

(2)栈的顺序存储代码

class Stack:
# 初始化空栈
    def__init__(self, size = 100):
        self.stack = []
        self.size = size 
        self.top = -1

# 判断栈是否为空
def is_empty(self):
    return self.top == -1

# 判断栈是否已满
def is_full(self):
    return self.top + 1 == self.size

# 入栈操作
def push(self, value):
    if self.is_full():
        raise Exception('Stack is full')

# 出栈操作
def pop(self):
    if self.is_empty():
        raise Exception('Stack is empty')
    else:
        self.top -= 1
        self.stack.pop()

# 获取栈顶元素
def peek(self):
    if self.is_empty():
        raise Exception('Stack is empty')
    else:
        return self.stack(self.top)

5 栈的链式存储

堆栈的顺序存储结构保留着顺序存储分配空间的固有缺陷,即在栈满或者其他需要重新调整存储空间时需要移动大量元素。为此,堆栈可以采用链式存储的方式来实现。在python中通过构造链表节点Node的方式来实现。这种采用链式存储结构的堆栈也被称为链式栈。

---->基本描述

# self.top 指向栈顶元素所在节点

  • 初始化空栈:使用链表创建一个空栈,并令栈顶元素指针self.top指向None,即self.top=None。
  • 判断栈是否为空:当self.top==None时,说明堆栈为空,返回True,否则返回False。
  • 获取栈顶元素:先判断堆栈是否为空,为空直接抛出异常。不为空则返回self.top指向的栈顶元素,即self.top.value。
  • 插入元素(进栈、入栈):创建值为value的链表节点,插入到链表头节点之前,并令栈顶指针self.top指向新的头节点。
  • 删除元素(出栈、退栈):先判断堆栈是否为空,为空直接抛出异常。如果堆栈不为空,则令self.top链表移动1位,并返回self.top.value。
class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

class Stack:
# 初始化空栈
    def__init__(self): 
        self.top = None

# 判断栈是否为空
def is_empty(self):
    return self.top == None

# 入栈操作
def push(self, value):
    cur = Node(value)
    cur.next = self.top
    self.top = cur
    
# 出栈操作
def pop(self):
    if self.is_empty():
        raise Exception('Stack is empty')
    else:
        cur = self.top
        self.top = self.top.next
        del cur

# 获取栈顶元素
def peek(self):
    if self.is_empty():
        raise Exception('Stack is empty')
    else:
        return self.top.value

 6 练习

(1)有效括号

给定一个只包括圆括号、中括号、花括号的字符串s,判断字符串是否有效。

有效字符串需要满足:

  • 左括号必须用相同类型的右括号进行闭合;
  • 左括号必须以正确的顺序闭合;
eg:
s = "()"
true

s = "() [] {}"
true

解题思路

  • 首先根据字符串长度,直接排除掉奇数长度的字符串,因为括号是成对出现的,所以字符串的长度应该为偶数,而长度 为奇数的字符串一定不匹配,直接返回False
  • 然后遍历整个字符串s。当遇到左括号时,将其入栈;当遇到右括号时,先判断当前栈顶元素是否是相同类型的左括号,如果是,则左括号出栈,继续向下方遍历;如果不是,则不匹配,直接返回False
  • 最后遍历完再判断一下栈是否为空,如果栈为空,则匹配成功,返回True;如果栈还有元素,则匹配失败,返回False
class Solution:
    def isValid(self, s:str)->bool:  # 检查对象变量是否已经实例化
        if len(s) % 2 == 1:
            return False

        stack = list()
        for cn in s:
            if cn == '(' or cn == '[' or cn == '{':
                stack.append(cn)
            elif cn == ')':
                if len(stack) != 0 and stack[-1] == '(':
                    stack.pop()
                else:
                    return False
            
            elif cn == ']':
                if len(stack) != 0 and stack[-1] == '[':
                    stack.pop()
                else:
                    return False
            
            elif cn == '}':
                if len(stack) != 0 and stack[-1] == '{':
                    stack.pop()
                else:
                    return False

        if len(stack) == 0:
            return True
        else:
            return False

(2)逆波兰表达式求值

逆波兰表达式又称后缀表达式,其特点是没有括号,运算符总是放在与他相关的操作数之后。逆波兰表达式的计算遵循从左到右的规律,在计算逆波兰表达式的值时,可以使用一个栈来存放当前的操作数,从左到右依次遍历逆波兰表达式,计算出对应的值:

  • 使用列表stack作为栈存放操作数,然后遍历表达式的字符串数组
  • 如果当前字符为运算符,则取出栈顶两个元素,在进行对应的运算之后,再将运算结果入栈
  • 如果当前字符为数字,则直接将数字入栈
  • 当遍历结束后,栈中最后剩余的元素就是最终的计算结果
class Solution:
    def evalRPN(self, tokens:List[str])->int:
        stack = []
        for token in tokens:
            if token == '+':
                stack.append(stack.pop() + stack.pop())
            elif token == '-':
                stack.append(-stack.pop() + stack.pop())
            elif token == '*':
                stack.append(stack.pop() * stack.pop())
            elif token == '/':
                stack.append(1 / stack.pop() * stack.pop())
            else:
                stack.append(int(token))
        return stack.pop()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

OR_0295

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

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

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

打赏作者

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

抵扣说明:

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

余额充值