如何在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); }