数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退

1.栈

操作受限的线性表,只能在一端插入和删除数据。

数组实现栈:顺序栈
链表实现栈:链式栈

#python实现顺序栈
class ArrayStack:
    def __init__(self,n):
        self.stack = []
        self.limit = n
        self.count = 0

    def push(self,item):
        if self.count == self.limit:
            return False

        self.stack.append(item)
        self.count += 1
        return True

    def pop(self):
        if self.stack:
            return self.stack.pop()
            self.count -= 1
        else:
            return None

    def peek(self):
        if self.stack:
            return self.stack[-1]

    def is_empty(self):
        return not self.count

    def size(self):
        return self.count

出栈:O(1)
入栈:O(1)
栈满时需要复制到一个新的数组中,均摊时间复杂度下来也是O(1)

2.栈在函数调用中的应用

函数调用的临时变量储存在栈中,每进入一个函数。临时变量会作为栈帧储存在栈中,函数执行完,对应的栈帧出栈。


int main() {
     
   int a = 1; 
   int ret = 0;
   int res = 0;
   ret = add(3, 5);
   res = a + ret;
   printf("%d", res);
   reuturn 0;
}

int add(int x, int y) {
     
   int sum = 0;
   sum = x + y;
   return sum;
}

数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第1张图片
为什么函数调用要用栈呢?
函数调用符合先进后出的特性。

3.栈在表达式求值中的应用

表达式求值一般是用两个栈,其中一个保存操作数的栈,另一个是保存运算符的栈。我们从左向右遍历表达式,当遇到数字,我们就直接压入操作数栈;当遇到运算符,就与运算符栈的栈顶元素进行比较。
如果比运算符栈顶元素的优先级高,就将当前运算符压入栈;如果比运算符栈顶元素的优先级低或者相同,从运算符栈中取栈顶运算符,从操作数栈的栈顶取 2 个操作数,然后进行计算,再把计算完的结果压入操作数栈,继续比较。
数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第2张图片
但是在写代码的过程中,我发现,仅仅比较优先级,但是由于存储在栈中的依然是字符,还是要通过判断是否为‘±*/()’来做真正的运算,最后查了一下选择了以下这种用一个栈的方法。
详细介绍如下:
https://mp.weixin.qq.com/s?__biz=MzAxODQxMDM0Mw==&mid=2247484903&idx=1&sn=184beaad36a71c9a8dd93c41a8ba74ac&chksm=9bd7fbefaca072f9beccff92a715d92ee90f46c297277eec10c322bc5ccd053460da6afb76c2&scene=21#wechat_redirect
主要思路:
将数字作为一个个的符号数字对,存储在栈中,遇到加减号可以直接存储,乘除号先计算再存储。
场景一,只计算“+”“-”“*”“/”和“ ”的式子


class Solution:
    def calculate(self, s: str) -> int:

        stack = []

        sign = '+'
        num = 0

        for i in range(len(s)):
            c = s[i]

            if c.isdigit():
                num = num * 10 + int(c)
           
           //当这位不是数字且不是空格的时候,或者是最后一位数的时候,就要把num存入栈中 
            if  (not c.isdigit() and c != ' ') or i+1 == len(s):
                
                if sign == '+':
                    stack.append(num)
                elif sign == '-':
                    stack.append(-num)
                elif sign == '*':
                    stack[-1] = stack[-1]*num
                elif sign == '/':
                    stack[-1] = int(stack[-1]/num)

                num = 0
                sign = c
        
        return sum(stack)

场景2:计算存在‘(’ ‘)’的场景

class Solution:
    def calculate(self,s):
        num,i = self.helper(s)
        return num
    
    def helper(self,s):
        stack = []
        sign = '+'
        num = 0
        i = -1
        while i < len(s)-1:
            i = i+1
            c = s[i]
            
            if c.isdigit():
                num = num*10+int(c)
            
            if c == '(':
                num,index = self.helper(s[i+1:])
                i = i+index+1
            if (not c.isdigit() and c!=' ') or i+1==len(s):
                if sign=='+':
                    stack.append(num)
                elif sign == '-':
                    stack.append(-num)
                elif sign == '*':
                    stack[-1] = stack[-1]*num
                elif sign == '/':
                    stack[-1] = int(stack[-1]/num)

                num = 0
                sign = c
            if c == ')':
                break
        return sum(stack),i
from collections import deque                                               
class Solution:
    def calculate(self, s: str) -> int:
        s = deque(s)

        def helper(s):
            stack = []
            num = 0
            sign = '+'

            while len(s)>0:
                c = s.popleft()

                if c.isdigit():
                    num = num*10 + int(c)

                if c =='(':
                    // 直接在s上pop,可以不用管返回的时候的i在什么位置
                    num = helper(s)
                
                if (not c.isdigit() and c !=' ') or len(s)==0:
                    if sign == '+':
                        stack.append(num)
                    elif sign == '-':
                        stack.append(-num)
                    elif sign == '*':
                        stack[-1] = stack[-1]*num
                    elif sign == '/':
                        stack[-1] = int(stack[-1]/num)

                    num = 0
                    sign = c
                
                
                if c == ')':
                    break
            return sum(stack)

        return helper(s)

4.栈在括号匹配中的应用

从左到右扫描字符串:
扫描到左括号时,入栈;
扫描到右括号时,从栈顶取出左括号,看是否匹配。
这里可以用字典来判断是否匹配:
dic = {’)’:’(’,’}’:’{’,’]’:’[’}
if dic[c] != cc
扫描中若遇到不匹配或者栈为空,则为非法格式。

字符串扫描完之后,还要检查栈是否为空!!
若不为空则还有未匹配的左括号,为非法格式。

class Solution:
    def isValid(self, s: str) -> bool:

        dic  = {
     ')':'(','}':'{',']':'['}
        stack = []

        for c in s:
            if c in dic:
                cc = stack.pop() if stack else '#'
                if dic[c] != cc:
                    return False
            else:
                stack.append(c)
        
        return not stack

5.浏览器的前进和后退

使用两个栈,X,Y
首次浏览的页面压入X栈
后退时先从X出栈,再将数据入栈Y
前进时从Y出栈,放入X中
如下图所示,顺序查看a,b,c三页面
数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第3张图片
回退到a页面:
数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第4张图片
前进到b页面:
数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第5张图片
查看d页面,此时c页面无法通过前进,后退查看,清空栈Y:
数据结构与算法专题汇总(六)栈,python实现栈,栈的应用和代码实现:函数调用,表达式求值,括号匹配,浏览器前进与后退_第6张图片

你可能感兴趣的:(数据结构与算法,数据结构,算法,python,栈)