不幸的是,一个项目只能通过“pop”从堆栈中删除。堆栈没有“删除”方法或类似的东西,但我有一个堆栈(是的,我需要一个堆栈!),我需要从中删除一些元素。
这样做有诀窍吗?
如果您需要删除不在顶部的项目,那么您需要的不是堆栈。
尝试从列表中实现自己的堆栈。然后您可以实现自己的推送和弹出功能(在列表中添加和删除),以及您自己的特殊 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);
}
}
考虑使用不同的容器。也许是一个链表。然后你可以使用
添加优先 最后添加 删除最后一个 删除优先
就像从堆栈中弹出/推送一样,您可以使用
消除
从列表中间删除任何节点
您可以使用LinkedList
基于列表的删除可能效率较低。在通过引用删除基于列表的堆栈将有 O(N) 搜索和 O(N) 调整大小。LinkedList 搜索是 O(N),删除是 O(1)。对于按索引删除,LinkedList 应该有 O(N) 遍历和 O(1) 删除,而 List 将有 O(1) 遍历(因为它是索引)和由于调整大小而导致 O(N) 删除。
除了效率之外,LinkedList 实现将使您保留在标准库中,从而使您的代码具有更大的灵活性并减少您编写的代码。
这应该能够处理 Pop、Push 和 Remove
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
}
也许扩展方法会起作用,但我怀疑确实需要完全不同的数据结构。
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;
}
}
在真正的堆栈中,这只能通过一种方式完成 -
弹出所有项目,直到删除您想要的项目,然后以适当的顺序将它们推回堆栈。
但是,这不是很有效。
如果你真的想从任何位置删除,我建议从 List、LinkedList 或其他集合构建一个伪堆栈。这将使您可以轻松地执行此操作。
那么它不是堆栈吗?堆栈是LAST in FIRST out
. 您将不得不编写一个自定义的或选择其他的。
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);
我在多毛情况下使用的一个技巧是在堆栈中的项目中添加一个“不推荐使用”标志。当我想“删除”一个项目时,我只需升起该标志(并清理该对象占用的任何资源)。然后,当 Pop() 处理项目时,我只需检查标志是否被提升,然后在循环中再次弹出,直到找到未弃用的项目。
do
{
obj = mQueue.Pop();
} while (obj.deprecated);
您可以管理自己的项目计数以了解队列中仍有多少“真实”项目,如果多线程解决方案需要,显然应该使用锁定。
我发现对于不断流经它们的队列 - 推送和弹出的项目 - 以这种方式处理它会更有效,它是你可以获得的最快的(支付 O(1) 从中间删除一个项目)和内存明智如果保留的对象很小,那么项目是否以合理的速度流动几乎是无关紧要的。
Stack<> 的构造函数将 IEnumerable<> 作为参数。因此可以执行以下操作:
myStack = new Stack<item>( myStack.Where(i => i != objectToRemove).Reverse() );
这在许多方面都是非性能的。
嗯......我同意前两个答案,但如果你想破解你的方式,只需弹出并保存所有元素,直到你找到你想要的,然后重新推送它们
是的,是丑陋的,性能不佳的,可能是奇怪的代码,需要很长的注释来解释原因,但你可以做到......
我遇到了这个问题。在我的代码中,我创建了自己的扩展方法:
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);
我使用了一个列表并添加了一些扩展方法,例如,
public static IThing Pop(this List<IThing> 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<IThing> 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<IThing> 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<IThing> list, int index, IThing thing)
{
if (list == null || index > list.Count || index < 0) return;
list.Insert(index, thing);
}
这仍然处理整个堆栈,但它是删除条目的替代方法。但是,按照这种方式编写,如果同一条目在堆栈中多次出现,它将全部删除。
using System.Collections.Generic;
namespace StackTest
{
class Program
{
static void Main(string[] args)
{
Stack<string> stackOne = new Stack<string>();
stackOne.Push("Five");
stackOne.Push("Four");
stackOne.Push("Three");
stackOne.Push("Two");
stackOne.Push("One");
deleteStackEntry(stackOne, @"Three");
deleteStackEntry(stackOne, @"Five");
}
static void deleteStackEntry(Stack<string> st, string EntryToDelete)
{
// If stack is empty
if (st.Count == 0) return;
// Remove current item
string currEntry = st.Pop();
// Remove other items with recursive call
deleteStackEntry(st, EntryToDelete);
// Put all items back except the one we want to delete
if (currEntry != EntryToDelete)
st.Push(currEntry);
}
}
}