如何在C#中删除不在堆栈顶部的堆栈项

不幸的是,一个项目只能通过“pop”从堆栈中删除。 堆栈没有“删除”方法或类似的东西,但我有一个堆栈(是的,我需要一个堆栈!),我需要从中删除一些元素。

有这个诀窍吗?

如果您需要删除不在顶部的项目,那么您需要的不是堆栈。

尝试从List中创建自己的堆栈实现。 然后,您可以实现自己的推送和弹出function(在列表中添加和删除),以及您自己的特殊PopFromTheMiddlefunction。

例如

public class ItsAlmostAStack { private List items = new List(); 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); } } 

考虑使用不同的容器。 也许是LinkedList。 然后你可以使用

  addfirst仅
 addlast仅
 RemoveLast
 RemoveFirst 

就像从堆栈中弹出/推送一样,你可以使用

 去掉 

从列表中间删除任何节点

也许扩展方法可行,但我怀疑完全需要完全不同的数据结构。

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

您可以使用LinkedList

基于列表的删除可能效率较低。 在通过引用移除基于列表的堆栈将具有O(N)搜索和O(N)resize。 LinkedList搜索是O(N),删除是O(1)。 对于按索引删除,LinkedList应该有O(N)遍历和O(1)删除,而List将有O(1)遍历(因为它是索引)和O(N)删除由于resize。

除了效率之外,LinkedList实现将使您保持在标准库中,打开您的代码以获得更大的灵活性并让您减少编写。

这应该能够处理Pop,Push和Remove

  public class FIFOStack : LinkedList { public T Pop() { T first = First(); RemoveFirst(); return first; } public void Push(T object) { AddFirst(object); } //Remove(T object) implemented in LinkedList } 

在真正的堆栈中,这只能以一种方式完成 –

弹出所有项目,直到删除所需的项目,然后按适当的顺序将它们推回到堆栈中。

但这并不是很有效。

如果你真的想从任何位置删除,我建议从List,LinkedList或其他一些集合构建一个伪栈。 这样可以让您轻松完成控制。

  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); 

然后它不是堆栈对吗? 堆栈LAST in FIRST out 。 您必须编写自定义或选择其他内容。

Stack <>的构造函数将IEnumerable <>作为参数。 所以可以执行以下操作:

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

这在许多方面都不具备性能。

我在毛茸茸的情况下使用的技巧是在堆栈中的项目中添加“已弃用”标志。 当我想“删除”一个项目时,我只需要提升该标志(并清理该对象所占用的所有资源)。 然后当Pop()项目时,我只是检查标志是否被引发,然后在循环中再次弹出,直到找到未弃用的项目。

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

您可以管理自己的项目计数,以了解队列中仍有多少“真实”项目,如果multithreading解决方案需要,则显然应该使用锁定。

我发现对于持续流过它们的队列 – 推送和弹出的项目 – 以这种方式处理它的效率要高得多,它可以获得最快的速度(支付O(1)从中间移除项目)和内存明智如果保留的对象很小,那么如果项目以合理的速度流动则几乎无关紧要。

嗯……我同意前两个答案,但是如果你想要破解你的方式只需弹出并保存所有元素,直到你找到你想要的那个,然后重新推动它们

是丑陋,表现糟糕,可能是奇怪的代码需要长时间的评论来解释原因,但你可以做到….

我遇到了这个问题。 在我的代码中,我创建了自己的扩展方法:

 public static class StackExtensions { public static void Remove(this Stack myStack, ICollection elementsToRemove) { var reversedStack = new Stack(); 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); 

我使用了一个列表并添加了一些扩展方法,例如,

 public static IThing Pop(this List list) { if (list == null || list.Count == 0) return default(IThing); // get last item to return var thing = list[list.Count - 1]; // remove last item list.RemoveAt(list.Count-1); return thing; } public static IThing Peek(this List list) { if (list == null || list.Count == 0) return default(IThing); // get last item to return return list[list.Count - 1]; } public static void Remove(this List list, IThing thing) { if (list == null || list.Count == 0) return; if (!list.Contains(thing)) return; list.Remove(thing); // only removes the first it finds } public static void Insert(this List list, int index, IThing thing) { if (list == null || index > list.Count || index < 0) return; list.Insert(index, thing); }