2012-07-16 30 views
1

我有一個方法將一個數組作爲參考傳遞,我使用遞歸來多次調用這個方法。我使用數組作爲「堆棧」。該代碼是一個計算器,將後綴轉換爲中綴,只是一個簡單的工具。Objective C:將NSArray作爲參考傳遞給方法

我有一個關於代碼和它的輸出的問題。該代碼的作品,但當我取消註釋一個部分[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; 
} 
+0

複製的行爲獨立於源。所以,答案應該是No. – rshahriar 2012-07-16 06:38:50

回答

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,在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,所以descriptionTop:遞歸調用上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。當我們在operand2上遞歸調用descriptionTop:時,它將返回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))" 
+0

這個反應非常驚人,解決了我一直遇到的所有問題,我知道如果我將代碼附加到遞歸調用的格式中,那麼操作數就會切換,這就是爲什麼我使用了副本,但是您的方法更簡單並且工作正常,再次感謝你的回覆和描述 – 2012-07-17 00:01:40

0

你叫[stack removeLastObject]兩次。當您的stack數組剩下一個元素時,代碼將失敗,因爲您首先刪除最後一個對象,然後(如果是NSString),則嘗試再次刪除最後一個元素,但沒有剩下對象。

+0

那你會建議我把[stack removeLastObject]然後呢? – 2012-07-16 06:28:01

+0

即時通訊試圖讓方法結束時堆棧爲0。我不認爲它會被調用兩次,因爲當值是一個操作,即+或 - 時,它只會轉到[stack removeLastObject]。當我遞歸調用它時,我也傳遞副本,然後它會從副本或原始堆棧中移除一個對象? – 2012-07-16 06:32:48

+0

如果在處理之前檢查輸入或處理了輸入錯誤,那麼將不會有NSString元素類型的堆棧,因爲輸入將是後綴表達式。 – rshahriar 2012-07-16 06:37:43