数据结构之栈

1、概念

栈:后进先出的序列
队列:先进先出的序列

2、实现方式

2、1基本方法

1、创建
2、检查
3、压人
4、弹出
5、输出栈顶/队前元素

2、2栈

顺序表:采用尾端插入删除,实现入栈和出栈;
链表:采用前端插入和删除,实现入栈和出栈;

2、3栈的应用

方便的保存和取用信息
先进后出性质可以有特殊应用
eg: 括号匹配问题
eg:表达式的计算和转换

3、栈的实现

# 定义栈的异常
class stackUnderflow(ValueError):
    pass
# 栈的顺序表实现:
class sstack:
    def __init__(self):
        self.elems = []

    def is_empty(self):
        return self.elems == []

    def push(self, elem):
        self.elems.append(elem)

    def pop(self):
        if self.elems == []:
            raise stackUnderflow('in stack top!')
        return self.elems.pop()

    def top(self):
        if self.elems == []:
            raise stackUnderflow('in stack top!')
        return self.elems[-1]


# 链表实现
class Node:
    def __init__(self, elem, next_=None):
        self.elem = elem
        self.next_ = next_


class lstack:
    def __init__(self):
        self._head = None

    def is_empty(self):
        return self._head is None

    def top(self):
        if self._head is None:
            raise stackUnderflow('in stack top!')
        point = self._head
        self._head = self._head.next_
        return self._head.elem

    def push(self, elem):
        node = Node(elem)
        if self._head is None:
            self._head = node
        else:
            node.next_ = self._head
            self._head = node

    def pop(self):
        if self._head is None:
            raise stackUnderflow('in stack top!')
        point = self._head
        self._head = point.next_
        return point.elem


# 测试
s1 = sstack()
for i in range(3):
    s1.push(i)
try:
    while (s1):
        print(s1.pop(), end=' ')
    print('\n')
except stackUnderflow as e:
    print('\nstack has exported all elems!')
print('\n')
s2 = lstack()
for i in range(3):
    s2.push(i)
try:
    while (s2):
        print(s2.pop(), end=' ')
    print('\n')
except stackUnderflow as e:
    print('\nstack has exported all elems!')

4、栈的应用

4.1栈的应用 括号的匹配 利用栈先进后出的特性来实现

# 从一个字符串中匹配出括号:首先括号集合要有;然后入栈的元素集合要有;括号匹配关系的集合要有;  
def check_parens(text):
    parens = '()[]{}'
    open_parens = '([{'
    opposite = {')': '(', ']': '[', '}': '{'}
    # 开括号入栈
    def parentheses(text):
        i, text_len = 0, len(text)
        while (True):
            while i < text_len and text[i] not in parens:
                i += 1
            if i >= text_len:
                return
            yield text[i], i
            i += 1

    st = sstack()  # 保存括号的栈 这里使用的顺序表形式的栈
    for pr, i in parentheses(text):
        if pr in open_parens:
            st.push(pr)
        elif st.pop() != opposite[pr]:
            print('Unmatching is found at ', i, ' for ', pr)
            return False
        # else: 这次匹配成功什么也不做
    print('All parentheses are correctly matched!')
    return True


text = 'afa(aklfa{afjha[Lalk;fka;f]alkfaf[afalla]})'
check_parens(text)

4.2 表达式的计算、变换

4.2.1后缀表达式的计算

#################################################
# 表达式的计算变换过程:这里假定输入表达式是字符串,项之间是空格 ###########################################################
# 输入:字符串,项之间是空格
# 输出:计算结果
##########################################################

# 定义一个新的栈类来存储计算过程的临时数据
# 不足两个元素时计算失败,当栈中只有一个元素时结束计算。
class esstack(sstack):
    def depth(self):
        return len(self.elems)


# 将字符行分隔为项的表
def suffix_exp_evaluator(line):
    return suf_exp_evaluator(line.split())

def suf_exp_evaluator(exp):  # exp是一个列表
    operators = '+-*/'
    st = esstack()
    for x in exp:
        if x not in operators:
            st.push(float(x))
            continue
        if st.depth() < 2:
            raise SytaxError('short of operand(s).')
        a = st.pop()
        b = st.pop()

        if x == '+':
            c = b + a
        elif x == '-':
            c = b - a
        elif x == '*':
            c = b * a
        elif x == '/':
            if a == 0:
                raise zeroDivisionError(str(b) + '/' + str(a))
            c = b / a
        else:
            break
        st.push(c)
    if st.depth() == 1:
        return st.pop()
    raise SytaxError('Extra operand(s).')


# 使用suffix_exp_evaluator(line)完成 计算
# 定义一个交互式的驱动函数
def suffix_exp_caculator():
    while True:
        try:
            line = input('Suffix Expression: ')  # 有输入,所以是交互式的
            #line = '1 2 + 3 4 + * 27 - 2 1 + /'
            if line == 'end': return
            res = suffix_exp_evaluator(line)
            print(res)
        except Exception as ex:
            print('Error: ', type(ex), ex.args)
#测试
#text = '1 2 + 3 4 + * 27 - 2 1 + /'
suffix_exp_caculator()

4.2.2 中缀表达式转化为后缀表达式

#####################################################################
# 中缀表达式,转化为后缀表达式    #####################################################################
#定义生成器
def tokens(text):
    text = text.split()
    for i in text:
        yield i
# 定义优先级和运算符集合
priority = {'(': 1, '+': 3, '-': 3, '*': 5, '/': 5}  # 定义优先级
infix_operators = '+-*/()'  # 定义运算符集合


def trans_infix_suffix(line):
    st = sstack()
    exp = []
    # 对x的情况分析:
    # 1、是数字;2、是左括号;3、是右括号;4、是运算符
    # 数字就直接存入表中,左右括号决定着几个运算符的连续压人表中,
    # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
    for x in tokens(line):  # tokens 是一个带定义的生成器
        if x not in infix_operators:
            exp.append(x)
        elif st.is_empty() or x == '(':  # 左括号进栈
            st.push(x)
        elif x == ')':  # 处理右括号分支
            while not st.is_empty() and st.top() != '(':
                exp.append(st.pop())
            if st.is_empty():  # 没找到左括号,就不匹配
                raise SyntaxError("Missing '('.")
            st.pop()  # 弹出左括号,右括号也不进栈
        else:
            while (not st.is_empty() and priority[st.top()] >= priority[x]):
                exp.append(st.pop())  # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
            st.push(x)

    while not st.is_empty():
        if st.top() == '(':
            raise SyntaxError("Extra '('.")
        exp.append(st.pop())
    return exp


# 测试函数
def test_trans_infix_suffix(text):
    print(text)
    print(trans_infix_suffix(text))
    print('value: ', suf_exp_evaluator(trans_infix_suffix(text)))

#测试
text = '( ( 1 + 2 ) * ( 3 + 4 ) - 27 ) / ( 2 + 1 )'
#text = '( 1 + 2 ) * ( 3 + 4 ) - 27'
test_trans_infix_suffix(text)

4.2.3 中缀表达式的计算

  #################################################   
      # 中缀表达式的求值  
    ############################################################
        #法1:利用后缀表达式计算来实现
        #输入:以空白作为分隔
        #输出:一个计算结果
        `###################################################################################`
        line = input('Infix Expression: ')
        value = suf_exp_evaluator(trans_infix_suffix(line))
        print(value)
        #法2:直接计算
        #运算符的优先级;括号作用;确定完成各运算的时机;做某个运算,找到正确的运算对象;这里是改进了中缀表达式转换为后缀表达式来实现的;将原本的运算符压人exp的数据栈,变为直接计算运算符,并将结果入栈
        #定义生成器
        def tokens(text):
            text = text.split()
            for i in text:
                yield i
        # 定义优先级和运算符集合
        priority = {'(': 1, '+': 3, '-': 3, '*': 5, '/': 5}  # 定义优先级
        infix_operators = '+-*/()'  # 定义运算符集合
        def infix_exp_evaluator(line):
            st = sstack()
            exp = []
            # 对x的情况分析:
            # 1、是数字;2、是左括号;3、是右括号;4、是运算符
            # 数字就直接存入表中,左右括号决定着几个运算符的连续压人表中,
            # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
            for x in tokens(line):  # tokens 是一个带定义的生成器
                if x not in infix_operators:
                    exp.append(float(x))
                elif st.is_empty() or x == '(':  # 左括号进栈
                    st.push(x)
                elif x == ')':  # 处理右括号分支
                    while not st.is_empty() and st.top() != '(':
                        a = exp.pop()
                        b = exp.pop()
                        operator = st.pop()
                        c = caculate(b,a,operator)
                        exp.append(c)
                    if st.is_empty():  # 没找到左括号,就不匹配
                        raise SyntaxError("Missing '('.")
                    st.pop()  # 弹出左括号,右括号也不进栈
                else:
                    while (not st.is_empty() and priority[st.top()] >= priority[x]):
                        a = exp.pop()
                        b = exp.pop()
                        operator = st.pop()
                        c = caculate(b,a,operator) # 栈顶的运算符需要和后的一个运算符比较后,当比后一个运算符优先级高才能入表
                        exp.append(c)  
                    st.push(x)
        
            while not st.is_empty():
                if st.top() == '(':
                    raise SyntaxError("Extra '('.")
                a = exp.pop()
                b = exp.pop()
                operator = st.pop()
                c = caculate(b,a,operator)
                exp.append(c)
            return exp.pop()
        def caculate(b,a,operator):
            if operator == '+':
                c = b + a
            elif operator == '-':
                c = b - a
            elif operator == '*':
                c = b * a
            elif operator == '/':
                if a == 0:
                    raise zeroDivisionError(str(b) + '/' + str(a))
                c = b / a
            else:
                raise Exception(str(b) + operator + str(a))
            return c
        # 测试
        line = '( ( 1 + 2 ) * ( 3 + 4 ) - 27 ) / ( 2 + 1 )'
        infix_exp_evaluator(line)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值