1

我有一个将数组作为引用传递的方法,我使用递归多次调用此方法。我将数组用作“堆栈”。该代码用于将后缀转换为中缀的计算器,并且只是一个简单的工具。

我对代码及其输出有疑问。该代码有效,但是当我取消注释其中一个部分[stack removeLastObject];时,它停止工作并声称该数组为空。

我没有得到这个,因为我正在从主数组中删除一个对象——而不是我在递归中使用的副本。如果我输入一个用于递归的副本,然后从原始对象中删除一个对象,该副本是否会受到影响?

我的主要示例是使用应输出 (3 + 5) 的 3、5、+ 数组。如果我取消注释我得到的一段代码(3+3)。这是代码:

+(NSString*) descriptionTop:(NSMutableArray *) stack{

NSMutableString *programFragment = [NSMutableString stringWithString:@""];

id topOfStack = [stack lastObject];
if (topOfStack) [stack removeLastObject];
NSLog(@"operation is %@", topOfStack);
NSLog(@"Stack is%@", stack);


if([ topOfStack isKindOfClass:[NSNumber class]]){
    [programFragment appendFormat:@"%g", [topOfStack doubleValue]];
}
else if( [topOfStack isKindOfClass:[NSString class]])
{
    NSString *operation = topOfStack;
    if ([operation isEqualToString:@"+"] || 
        [operation isEqualToString:@"-"] ||  
        [operation isEqualToString:@"/"] ||  
        [operation isEqualToString:@"*"]) {

       NSMutableArray *operand1 = [stack mutableCopy];
        [operand1 removeLastObject];

        NSMutableArray *operand2 = [stack mutableCopy];
        // [stack removeLastObject];

        [programFragment appendFormat:@"(%@ %@ %@)", [self descriptionTop:operand1], operation, [self descriptionTop:operand2]];

    }
 }

NSLog(@" program fragment returns %@", programFragment);
return programFragment;
}
4

2 回答 2

2

我想我理解你想要做什么,但你的逻辑相当混乱。假设您的额外内容未注释,让我们浏览一下您的输入代码(堆栈顶部在[3 5 +]哪里)。首先,您(正确地)从堆栈中弹出运算符:+[stack removeLastObject]

id topOfStack = [stack lastObject];
// topOfStack = +
// stack = [3 5 +]

if (topOfStack) [stack removeLastObject];
// topOfStack = +
// stack = [3 5]

然后你发现那topOfStack是一个字符串,所以你把它分配给operation. 然后你这样做:

        NSMutableArray *operand1 = [stack mutableCopy];
        // operation = +
        // operand1 = [3 5]
        // stack = [3 5]

        [operand1 removeLastObject];
        // operation = +
        // operand1 = [3]
        // stack = [3 5]

        [stack removeLastObject];
        // operation = +
        // operand1 = [3]
        // stack = [3]

请注意,此时,5 完全消失了!您的任何变量中都没有它。因此,当您设置时operand2, the3位于顶部(实际上是唯一的元素):

        NSMutableArray *operand2 = [stack mutableCopy];
        // operation = +
        // operand1 = [3]
        // stack = [3]
        // operand2 = [3]

现在,让我们回到我们设置的地方operand1,但删除额外的[stack removeLastObject]

        NSMutableArray *operand1 = [stack mutableCopy];
        // operation = +
        // operand1 = [3 5]
        // stack = [3 5]

        [operand1 removeLastObject];
        // operation = +
        // operand1 = [3]
        // stack = [3 5]

        NSMutableArray *operand2 = [stack mutableCopy];
        // operation = +
        // operand1 = [3]
        // stack = [3 5]
        // operand2 = [3 5]

现在operand25在顶部,因此对descriptionTop:on的递归调用会operand2找到,并且您会得到的5正确答案(3 + 5)[3 5 +]

但是这个功能还是坏了。

考虑输入[3 4 5 * +]。什么是正确的输出?我认为应该是(3 + (4 * 5))。但是你的函数是做什么的?让我们来看看它。首先,它弹出+操作符:

id topOfStack = [stack lastObject];
// topOfStack = +
// stack = [3 4 5 * +]

if (topOfStack) [stack removeLastObject];
// topOfStack = +
// stack = [3 4 5 *]

接下来,它将堆栈复制到operand1并从中删除最后一个元素operand1

    NSMutableArray *operand1 = [stack mutableCopy];
    // operation = +
    // operand1 = [3 4 5 *]
    // stack = [3 4 5 *]

    [operand1 removeLastObject];
    // operation = +
    // operand1 = [3 4 5]
    // stack = [3 4 5 *]

然后,假设我们不这样做[stack removeLastObject],它将堆栈复制到operand2

    NSMutableArray *operand2 = [stack mutableCopy];
    // operation = +
    // operand1 = [3 4 5]
    // stack = [3 4 5 *]
    // operand2 = [3 4 5 *]

现在你可以看到,当我们descriptionTop:operand1这里递归调用时,它会返回5。当我们递归调用descriptionTop:operand2,它会返回4 * 5。所以我们返回(5 + (4 * 5))。怎么了3?我们从未达到它!

这里的问题是,要到达3,我们必须将堆栈中的 用作一个操作数,然后在同一个堆栈(已消耗的位置)中查找另一个操作数,以便我们可以找到.4 5 *4 5 *3

您需要做的就是根本不复制堆栈!您需要将相同的堆栈对象传递给递归调用,这样当您弹出所有构成一个操作数的元素时,您可以在堆栈顶部找到另一个操作数的元素。像这样:

    // operation = +
    // stack = [3 4 5 *]

    NSString *operand2Description = [self descriptionTop:stack];
    // operation = +
    // operand2Description = "4 * 5"
    // stack = [3]

    NSString *operand1Description = [self descriptionTop:stack];
    // operation = +
    // operand1Description = "3"
    // operand2Description = "4 * 5"
    // stack = [] (empty stack)

    [programFragment appendFormat:@"(%@ %@ %@)", operand1Description, operation, operand2Description];
    // programFragment = "(3 + (4 * 5))"
于 2012-07-16T06:47:54.887 回答
0

你打[stack removeLastObject]了两次电话。当您的stack数组只剩下一个元素时,代码将失败,因为您首先删除了最后一个对象,然后(如果是NSString)您尝试再次删除最后一个元素,但没有留下任何对象。

于 2012-07-16T06:06:47.500 回答