2013-08-18 22 views
1

我想實現一個鏈表的對象,所以我有一個頭文件,像這樣一個節點類:消滅在Objective-C

@interface Node : NSObject 

@property(nonatomic,assign)int data; 
@property(nonatomic,strong) Node *right; 
@property(nonatomic,strong) Node *left; 

@end 

然後在另一個班,我分配他們然後調用一個方法來破壞一個給定值的所有出現:

Node *node0 = [[Node alloc]init]; 
Node *node1 = [[Node alloc]init]; 
Node *node2 = [[Node alloc]init]; 
Node *node3 = [[Node alloc]init]; 
Node *node4 = [[Node alloc]init]; 
node0.data = 1; 
node1.data = 2; 
node2.data = 5; 
node3.data = 5; 
node4.data = 3; 
node0.right = node1; 
node1.right = node2; 
node2.right = node3; 
node3.right = node4; 
node4.right = NULL; 
[self removeNodeWithValue:node0 value:5]; 
NSLog(@"node %d, %d, %d, %d, %d", node0.data, node1.data, node2.data, node3.data, node4.data); 

和這裏的方法本身:

-(void)removeNodeWithValue:(Node *)head value:(int)value 
{ 
    Node *toDelete; 
    while (head != NULL) { 
    if (head.data == value) 
    { 
     toDelete = head; 
     head = head.right; 
     toDelete = nil; 
    } 
    else 
    { 
     head = head.right; 
    } 
    } 
} 
==> 1, 2, 5, 5, 3 

我知道我可以更改實例,因爲如果我將toDelete = nil更改爲toDelete.data = 4,則輸出爲==> 1, 2, 4, 4, 3。我的問題是,我如何銷燬這些實例?謝謝。

+0

看到這個:http://stackoverflow.com/questions/14508134/whats-the-correct-way-destroy-different-kinds-of-objects-in-objective-c?rq=1 –

+0

他們建議設置對象爲零,但在我的代碼中,你可以看到這不起作用。 –

回答

3

看來你還沒有理解ARC如何工作。只要有強指針指向對象,對象就不會被釋放。在您的示例代碼中有兩個原因失敗:首先你始終保持較強的參考node0

Node *node0 = [[Node alloc]init]; 

只要這個指針沒有按照慣例NULL設置爲nil(記住,是用於常規指針,對象指針爲nil),節點不會被釋放。其次,如果要釋放的節點不是第一個節點,那麼另一個節點持有一個強指針指向它,這就是節點不會被釋放的另一個原因。保留另一個指向node0(您的情況爲toDelete)的指針將增加節點的節點保留計數,當您將其設置爲nil時,它將恢復爲原始值。

爲了正確地做到這一點,您還必須避免鏈刪除(如果第一個節點得到釋放,它將失去對第二個節點的強引用,如果沒有強指針,可能會釋放該引用,第三個節點將被釋放,等等)。

最後,我建議不要只是抱着一堆指針到每個節點,而不是實現一個鏈表類,會做添加/刪除節點的工作:

@interface List : NSObject 

@property (nonatomic, strong) Node* first; 
@property (nonatomic, weak) Node* last; 

@end 

// Inside the class implementation 

- (void) addNodeWithValue: (int) value 
{ 
    Node* node= [[Node alloc]init]; 
    node.data= value; 
    if(!first) 
    { 
     last= first= node; 
    } 
    else 
    { 
     last.right= node; 
     node.left= last; // left should be a weak property 
     last= node; 
    } 
} 

- (void) removeNodeWithValue: (int) value // O(n) method 
{ 
    Node* ptr= first; 
    while(ptr) 
    { 
     if(ptr.data== value) 
     { 
      if(ptr== first) 
      { 
       first= last= nil; 
      } 
      else 
      { 
       ptr.left.right= ptr.right; 
       ptr.right.left= ptr.left; 
      } 
      break; // Remove the break if you want to remove all nodes with that value 
     } 
     ptr= ptr.right; 
    } 
} 

我的天堂」沒有測試過這個代碼,我不能保證它能正常工作。

+0

這刪除了'5's'中的一個,我嘗試使它遞歸移除其他五個,但無濟於事。 –

+0

@ meta150這段代碼只刪除一個值,如果你想刪除它們,你必須在循環中刪除break指令(由評論 - 我編輯了答案)。 –

0

所以你想清除具有指定值的所有節點。首先,你的測試是無效的,因爲你有明確的引用所有的節點,所以即使它們從你的節點結構中清除,你的測試日誌仍然會打印出來。其次,當它沒有發現被測節點具有指定值時,您的刪除方法需要通過節點結構遞歸調用。第三,節點不應該自己測試,它應該測試leftright節點值(由於節點不知道它的父節點,所以節點不能刪除它自己)。

所以,像這樣:

-(void)removeNodeWithValue:(Node *)head value:(int)value 
{ 
    if (head.right.data == value) 
    { 
     head.right = nil; 
    } 
    else 
    { 
     [self removeNodeWithValue:head.right value:value]; 
    } 

    if (head.left.data == value) 
    { 
     head.left = nil; 
    } 
    else 
    { 
     [self removeNodeWithValue:head.left value:value]; 
    } 
} 

這不測試根節點本身,因爲這應該開始前檢查,然後從控制器本身的頭項目。

0

你的問題不是刪除對象,而是指針。

指針就像指向包含內容(內存位置)的框的箭頭。當你做

toDelete = head; 
head = head.right; 
toDelete = nil; 

你只是刪除其中一個「箭頭」,它是poiting某個框,但不刪除框本身。

Wain的答案應該給出一個正確的方法。