弹出堆栈中的随机项

时间:2014-03-11 14:52:44

标签: c#

我似乎无法想象如何使用元素功能弹出堆栈的项目。有人可以告诉我该怎么做吗?

相关代码:

Stack<Cards> stackOfCards = new Stack<Cards>();

我之前已将物品放入此堆栈。

Random random = new Random();
int randomNumber = random.Next(0, 52);

for (int i = 0; i < 200; i++)
{
    stackOfCards.ElementAt(randomNumber);//how do i pop this?
}

P.S。堆栈是从0还是1开始?那么对于一副牌来说,它会是0-51还是1-52?

1 个答案:

答案 0 :(得分:7)

堆栈的重点是弹出随机元素。如果您需要从集合中删除随机项,请使用支持该集合的集合,例如List<T>

Stack是一个后进先出(LIFO)集合,而不是随机访问集合。

我建议阅读:http://en.wikipedia.org/wiki/Stack_(abstract_data_type)

如果您需要以随机顺序将放在堆栈上,我建议这样:

List<Cards> wholeDeck = new List<Cards> { // initialize with a complete deck }
Random r = new Random();
Stack<Cards> stackOfCards = new Stack<Cards>();
while (wholeDeck.Count > 0) {
    var aCard = wholeDeck[r.Next(0,wholeDeck.Count)];     // grab a random card
    stackOfCards.Push(aCard);                              // push it on the stack
    wholeDeck.Remove(aCard);                              // remove it from the original list
}

关于效率的说明(因为Servy买了它):Servy绝对正确,这不是最有效的洗牌方式。为什么?好吧,因为从列表中删除项目是O( n )并且您必须 n 次,所以总体来说它是O(n2 )。在列表中交换项目(如在Fisher-Yates算法中)是O(1),你做 n 次,所以总体来说它是O(n)。当然,您仍然需要将洗牌列表中的项目添加到堆栈中,该堆栈将是O(n),因此O(2n)。有52个项目,这可能差别很小(这就是为什么我选择不担心它),但如果你有数百万件物品,或者你正在洗牌一百万张牌,那么这可能是值得担心的事情。

现在我假设OP的原始问题是针对某种类的,目的是了解有关集合,它们如何工作以及它们有什么好处的东西,我认为这确实带来了一个重要的比较。不同的集合类型适用于不同的事物。 List为您提供对列表中任何项目的非常快速的O(1)随机访问,这使其成为一种出色的通用集合类型。但这需要付出代价。成本是列表的删除(以及插入,有时是添加)要慢得多。从列表中删除项目时,必须重新组织列表,以便在删除一个位置之后移动每个项目,这样您仍然可以快速索引它。当您插入(在某个仲裁索引处)时,您必须将项目向上移动以腾出空间。当您添加到列表的末尾时,可能需要调整后备存储的大小(在.NET中它是一个数组)以腾出空间(实际上插入时可能也是如此)这需要复制整个集合(.NET列表类通过设置初始容量来解决这个问题,当你达到该容量时,它会使容量增加一倍而不是仅增加一个元素)。因此,如果您需要一个集合,您将要插入和删除很多项目,那么List可能不是最佳选择。

那么Stack呢?只需让您从集合中的一个位置添加(推送)和删除(弹出),Stack就会解决插入和删除问题。这样添加和删除是O(1)(至少对于固定大小的堆栈)。哪个好。但成本是您现在无法以随机顺序访问集合中的项目。因此,为什么OP难以弄清楚如何在堆栈上混乱 。如果你需要堆栈上的 nth 项目,你必须将它上面的每个项目弹出一个临时堆栈,然后查看你想要的项目,然后再推回你删除的所有项目。

另一种集合类型是链表。此集合具有非常快速的删除(如果您有对节点的引用)和插入,您可以快速找到下一个(在双向链表的情况下最后一个)节点。但是找到 nth 节点是O(n),因为你必须遍历集合,计算节点才能找到它。

其他收藏品具有其他属性,在选择合适的收藏品之前了解您需要的内容非常重要。