【问题标题】:Python Stack Out of Bounds ErrorPython 堆栈越界错误
【发布时间】:2015-06-14 10:46:16
【问题描述】:

我的堆栈的push 方法出现索引越界错误。

我正在尝试在 python 中实现一个后缀样式的逻辑计算器。例如0!1&1!0=!1/| 将评估为 1 或 true。

我使用堆栈和与此类列表“push”和“pop”相关联的常用方法来实现这一点,但我不允许使用典型的附加或删除方法,在这种实现中可能会很好。相反,我必须将列表初始化为一个标准大小,该大小等于我将对其执行评估的表达式的长度。

我使用名为evaluate 的方法来执行此操作,方法是引用一个名为top 的全局整数,该整数指向堆栈的顶部,并根据我调用pushpop 而在其中递增或递减。

我的push方法如下

def push(stack, element):
    global tos
    tos += 1
    stack[tos] = element

我的pop方法如下

def pop(stack):
    #stack = None
    global tos
    tos -= 1

基本上,我使用

通读了字符串的每个单独元素
for i in expression

然后我说,if i ==(某种表达方式):执行预制方法。

这是我在这个循环中找到的、遍历表达式的代码中的几个示例

if op == "1":
    push(theStack, True)
elif op == "0":
    push(theStack, False)
elif op == "!":
    pop(None)
    push(theStack, Not(theStack[tos]))
elif op == "&":
    pop(None)
    pop(None)
    push(theStack, And(theStack[tos], theStack[tos + 1]))

我测试了pop,它似乎做了应该做的事。我认为错误在于我的push

我将tos 初始化为-1,这也是我的方法顶部的一个快速峰值,在

中找到了循环
def LogicalEval (expression):
    global tos
    theStack = [len(expression)]

    def Not(expr):
        if expr == True:
            return False
        else:
            return True

    def And (expr1, expr2):
        if expr1 == True and expr2 == True:
            return True
        else:
            return False

我不会在LogicalEval 之外的任何点启动堆栈,实际上我仅限于三个主要方法(pushpopLogicalEval)在我的辅助方法之外,例如@在LogicalEval 中找到的987654343@ 和Not

【问题讨论】:

  • 请修正格式。如果您在每行之前留 4 个空格,它将突出显示为代码。
  • 那么这里的栈是怎么定义的?
  • 另外,tosinitial 值是多少?
  • 另外我忘了提到我将 tos 初始化为 -1
  • @user3106485:您可以将其添加到您的问题中,只需 edit 即可。

标签: python list stack indexoutofboundsexception


【解决方案1】:

您创建了一个包含 一个 元素的堆栈:

theStack = [len(expression)]

len() 返回一个整数,因此您创建了一个包含 5 个字符的表达式,如下列表:

theStack = [5]

所以你会很快用完空间。

像这样创建列表:

theStack = [None] * len(expression)

一个序列上的乘法会重复该序列。 [None] 是一个包含一个元素(None 标记值)的列表,将其乘以表达式的长度会创建一个包含这么多元素的列表。

接下来,对于!&,您对堆栈上操作数的处理不正确:

elif op == "!":
    pop(None)
    push(theStack, Not(theStack[tos]))
elif op == "&":
    pop(None)
    pop(None)
    push(theStack, And(theStack[tos], theStack[tos + 1]))

您想要首先检索堆栈值,然后是pop();或调整您的 tos 偏移量以考虑到它们已经递减,或以其他方式更改您的 pop() 函数以返回弹出的值。

目前,当您运行!(布尔值NOT)时,您会从tos == 0 移动到tos == -1,然后将Not(theStack[-1]) 推回堆栈。这不是您想要在这里做的,因为theStack[-1]您堆栈中的最后一个元素,而不是当前活动堆栈的一部分。

然后你用tos == 2 在堆栈上执行&(布尔AND)并弹出两次。现在您再次位于0 并尝试寻址theStack[0]theStack[1]。这里堆栈的偏移量是完全不正确的;您刚刚从 tos 中删除了两个值,然后添加了 0 和 1,以解决 旧堆栈顶部下方的两个值

我个人会选择一个 pop() 函数,它返回堆栈顶部并调整 tos 指针:

def pop(stack):
    global tos
    tos -= 1
    return stack[tos + 1]  # value at old position

然后使用它从堆栈中获取您的操作数:

elif op == "!":
    push(theStack, Not(pop(theStack)))
elif op == "&":
    push(theStack, And(pop(theStack), pop(theStack)))

【讨论】:

  • 当堆栈顶部“tos”位于 0 位置时,我何时会在诸如“&”之类的二进制操作上调用 push?堆栈中必须至少有 2 个元素,这意味着堆栈/tos 顶部的最低索引将为 1。如果发生这种情况,则提供的表达式中将出现错误.. 而不是错误在我的代码中。然而,我确实觉得即使考虑到这一点,我的偏移量仍然可能有点偏离
  • @user3106485 对,这是我的错误;现在正在旅行,所以更正必须等待一分钟左右。对不起!
  • 嘿,我让一切工作正常,非常感谢您的帮助 Martijn Pieters!
【解决方案2】:

theStack = [len(expression)] 创建一个长度为 len(expression) 的列表 - 它创建一个长度为 1 的列表,在 theStack[0] 中包含值 len(expression)

要创建给定长度的列表,您可以这样做

theStack = [0] * len(expression)]

这会将theStacklen(expression) 元素初始化为零。

【讨论】:

  • 哦,好吧,你被双节棍打了:D
  • @AnttiHaapala:我应该知道比尝试忍者忍者 :)
猜你喜欢
  • 1970-01-01
  • 2019-07-08
  • 2014-01-27
  • 2020-04-23
  • 1970-01-01
  • 2016-03-14
  • 2012-01-05
  • 2016-04-12
  • 2017-09-23
相关资源
最近更新 更多