【问题标题】:Objective C: Passing NSArray as reference to method目标 C:传递 NSArray 作为方法的引用
【发布时间】:2012-07-14 23:07:43
【问题描述】:

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

我对代码及其输出有疑问。代码有效,但是当我取消注释 [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;
}

【问题讨论】:

  • 复制的行为独立于源。所以,答案应该是否定的。

标签: objective-c recursion stack nsarray pass-by-reference


【解决方案1】:

我想我理解你想要做什么,但你的逻辑相当混乱。假设您的额外 [stack removeLastObject] 未注释,让我们遍历输入 [3 5 +] 的代码(其中 + 是堆栈的顶部)。首先,你(正确地)从栈中弹出操作符:

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 时,3 位于顶部(实际上是唯一的元素):

        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]

现在operand2 在顶部有5,因此对operand2 上的descriptionTop: 的递归调用会找到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。当我们在operand2 上递归调用descriptionTop: 时,它将返回4 * 5。所以我们返回(5 + (4 * 5))3 怎么了?我们从未到达过它!

这里的问题是,为了到达3,我们必须使用堆栈中的4 5 *作为一个操作数,然后在中寻找另一个操作数相同的堆栈(其中4 5 * 已被消耗),以便我们可以找到3

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

    // 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))"

【讨论】:

  • 这个响应太棒了,解决了我遇到的所有问题,我知道如果我保留代码 appendformat 和递归调用,操作数会切换,这就是我使用副本但你的方式的原因更简单并且工作正常,再次感谢您的精彩回复和描述
【解决方案2】:

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

【讨论】:

  • 那你建议我把 [stack removeLastObject] 放在哪里?
  • 我试图在方法结束时使堆栈为 0。我不认为它会被调用两次,因为它只在值是操作即 + 或 - 时进入 [stack removeLastObject]。当我递归调用它时,我也在传递副本,然后它会从副本或原始堆栈中删除一个对象吗?
  • 如果在处理之前检查输入或处理输入错误,则不会有元素类型为 NSString 的堆栈,因为输入将是一个后缀表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
相关资源
最近更新 更多