2009-04-14 101 views
27

不幸的是,項目只能通過「pop」從堆棧中刪除。該堆棧沒有「刪除」方法或類似的東西,但我有一個堆棧(是的,我需要一個堆棧!),我需要從中刪除一些元素。如何刪除不在C#中堆棧頂部的堆棧項目

有沒有這樣做的把戲?

+0

這是功課?如果是這樣,請忽略我的答案,這可能不是你所需要的,用Reed Copsey的答案來代替:http://stackoverflow.com/questions/748387/how-to-remove-a-stack-item-which-is-not 748409#748409 – 2009-04-14 16:43:03

+3

不,它不是作業,它只是一個非常特殊的情況下的小型私人項目^^ – Enyra 2009-04-14 16:48:04

+0

彈出堆棧並拋棄值? – belgariontheking 2009-04-14 16:49:50

回答

39

如果您需要刪除不在頂部的項目,那麼您需要的東西不是堆棧。

嘗試從List中自己實現一個堆棧。然後你可以實現自己的推送和彈出功能(在列表中添加&刪除)以及你自己特殊的PopFromTheMiddle功能。

例如

public class ItsAlmostAStack<T> 
{ 
    private List<T> items = new List<T>(); 

    public void Push(T item) 
    { 
     items.Add(item); 
    } 
    public T Pop() 
    { 
     if (items.Count > 0) 
     { 
      T temp = items[items.Count - 1]; 
      items.RemoveAt(items.Count - 1); 
      return temp; 
     } 
     else 
      return default(T); 
    } 
    public void Remove(int itemAtPosition) 
    { 
     items.RemoveAt(itemAtPosition); 
    } 
} 
+10

圍繞現有容器進行自定義實現可以讓您做到所需。如果你需要像我這樣的雙端堆棧(destack),它還可以讓你編寫最令人敬畏的函數名稱:PushBottom(),PopBottom()和PeekBottom():)。 – xan 2009-04-14 16:41:40

11

考慮使用不同的容器。也許是一個LinkedList。 然後你可以使用

AddFirst 
AddLast 
RemoveLast 
RemoveFirst

就像流行/推從堆棧,你可以使用

Remove

從列表的中間

3

然後取出所有節點是不是堆疊對?堆棧是LAST in FIRST out。 你將不得不寫一個自定義的或選擇其他的東西。

4
Stack temp = new Stack(); 
    object x, y; 
    While ((x = myStack.Pop()) != ObjectImSearchingFor) 
     temp.Push(x); 
    object found = x; 
    While ((y = temp.Pop()) != null) 
     myStack.Push(y); 
0

hmmmm ......我同意前面的兩個答案,但如果你正在尋找破解你的方式是流行,並保存所有元素,直到你得到你想要的,並重新推他們都

是是醜陋的,不好執行,可能奇怪的代碼,將需要很長的註釋解釋爲什麼,但你可以做到這一點....

4

在真正的堆棧,這隻能做一種方式 -

彈出所有的項目,直到你刪除你想要的,然後推回去以適當的順序到堆棧。

雖然這不是非常有效。

如果你真的想從任何位置移除,我建議從List,LinkedList或其他集合構建一個僞堆棧。這會讓你輕鬆控制。

6

也許一個擴展方法可行,但我懷疑完全需要一個不同的數據結構。

public static T Remove<T>(this Stack<T> stack, T element) 
{ 
    T obj = stack.Pop(); 
    if (obj.Equals(element)) 
    { 
     return obj; 
    } 
    else 
    { 
     T toReturn = stack.Remove(element); 
     stack.Push(obj); 
     return toReturn; 
    } 
} 
1

堆棧<>的構造函數的IEnumerable <>作爲參數。因此,可以執行以下操作:

myStack = new Stack<item>(myStack.Where(i => i != objectToRemove).Reverse()); 

這在很多方面都不具有高性能。

1

我在毛茸茸的情況下使用的一個技巧是向堆棧中的項目添加「棄用」標記。 當我想'刪除'一個項目時,我只需提出該標誌(並清理該對象所佔用的任何資源)。 然後,當Pop()ing項目時,我只是檢查標誌是否被提出,並在循環中再次彈出,直到找到一個未被棄用的項目。

do 
{ 
    obj = mQueue.Pop(); 
} while (obj.deprecated); 

您可以管理自己的項目數知道許多「真實」的項目是如何仍在隊列中,顯然鎖定,如果這需要多線程解決方案應該被採用。

我發現,對於通過它們的不斷流動的隊列 - 物品推送和彈出 - 這樣更有效率,以最快速度獲得(支付O(1)用於從中間移除物品)和記憶方式,如果保留的對象很小,那麼如果項目以合理的速度流動,則大多數情況下不相關。

4

你可以使用一個LinkedList

列表基於去除將可能是低效率的。 通過引用刪除基於列表的堆棧將進行O(N)搜索和O(N)調整大小。 LinkedList搜索是O(N)並且移除是O(1)。 對於通過索引進行刪除,LinkedList應該進行O(N)遍歷和O(1)刪除,而List將由於調整大小而進行O(1)遍歷(因爲它是索引)和O(N)刪除。

除了效率,LinkedList實現將使您保持在標準庫中,打開代碼以獲得更大的靈活性,並讓您編寫更少的代碼。

這應該能夠處理彈出,推,並刪除

public class FIFOStack<T> : LinkedList<T> 
    { 
     public T Pop() 
     { 
      T first = First(); 
      RemoveFirst(); 
      return first; 
     } 

     public void Push(T object) 
     { 
      AddFirst(object); 
     } 

     //Remove(T object) implemented in LinkedList 
    } 
0

我碰到這個問題就來了。在我的代碼創建了自己的擴展方法:

public static class StackExtensions 
{ 
    public static void Remove<T>(this Stack<T> myStack, ICollection<T> elementsToRemove) 
    { 
     var reversedStack = new Stack<T>(); 

     while(myStack.Count > 0) 
     { 
      var topItem = myStack.Pop(); 
      if (!elementsToRemove.Contains(topItem)) 
      { 
       reversedStack.Push(topItem); 
      } 
     } 

     while(reversedStack.Count > 0) 
     { 
      myStack.Push(reversedStack.Pop()); 
     }   
    } 
} 

,我打電話給我的方法是這樣的:

var removedReportNumbers = 
selectedReportNumbersInSession.Except(selectedReportNumbersList).ToList(); 

selectedReportNumbersInSession.Remove(removedReportNumbers);