【问题标题】:Push a stack onto another stack将一个堆栈压入另一个堆栈
【发布时间】:2013-12-26 23:38:21
【问题描述】:

在 C# 中,有没有一种方法可以将一个堆栈推入另一个堆栈,而无需遍历堆栈元素?如果没有,我应该使用更好的数据结构吗?在 Java 中你可以这样做:

stack1.addAll(stack2)

我希望找到 C# 类比...

【问题讨论】:

  • 也许有点迟钝,但转换为ArrayList,然后使用msdn.microsoft.com/en-us/library/…,然后再转换回Stack?
  • 可以将每个堆栈复制到数组,然后使用 Array.Copy 合并数组,然后将数组加载到 ctor 中的新堆栈,但我想我会循环。
  • 哇,这是一个相当大的提示@rdodev,似乎 List 也有接近我所追求的 InsertRange() 方法,还有 AddRange() 这正是我在找什么。如果 AddRange 按我的预期工作,我会给你答案...
  • @ryan0 好,让我知道这是否适合您。

标签: c# .net stack


【解决方案1】:

0。安全解决方案 - 扩展方法

public static class Util {
        public static void AddAll<T>(this Stack<T> stack1, Stack<T> stack2) {
            T[] arr = new T[stack2.Count];
            stack2.CopyTo(arr, 0);

            for (int i = arr.Length - 1; i >= 0; i--) {
                stack1.Push(arr[i]);
            }
        }
    }

可能最好的方法是创建一个扩展方法。请注意,我将第一个堆栈“放在”另一个堆栈的“顶部”,可以说是通过从 arr.Length-1 循环到 0。所以这段代码:

  Stack<int> x = new Stack<int>();
  x.Push(1);
  x.Push(2);

  Stack<int> y = new Stack<int>();
  y.Push(3);
  y.Push(4);          

  x.AddAll(y);

将导致 x 为:4,3,2,1。如果您按下 1、2、3、4,这就是您所期望的。当然,如果您要遍历第二个堆栈并实际弹出元素,然后将它们推送到第一个堆栈,您最终会得到 1、2、4、3。同样,根据您认为合适的方式修改 for 循环。或者您可以添加另一个参数来指定您想要的行为。我手头没有Java,所以我不知道他们做什么。

话虽如此,您可以这样做,但我不保证它会继续工作。 MS 总是可以在调用 ToList 时更改堆栈工作方式的默认行为。但是,这更短,并且在具有 .NET 4.5 的 my 机器上的工作方式与上述扩展方法相同:

1 Line Linq 解决方案:

y.Reverse().ToList().ForEach(item => x.Push(item));

【讨论】:

  • 奇怪的是MSDN documentation 没有明确指定堆栈的枚举顺序,尽管它确实有一个示例。不过,ToArray 方法确实指定了 LIFO 顺序。
  • 我喜欢您的安全解决方案。这正是我想要的行为,同时仍然使用堆栈(当你在做类似堆栈的事情时,它们在概念上会更好)。
【解决方案2】:

在您的问题中,想要“不遍历堆栈元素”执行此操作基本上意味着基于LinkedList 的堆栈,您只需加入第一个和最后一个元素以在恒定时间内组合堆栈。

但是,除非您有非常具体的原因使用LinkedList,否则最好只迭代基于数组(基于List)的堆栈元素。

就具体实现而言,您可能应该澄清是希望第二个堆栈以相同的堆栈顺序添加到第一个堆栈中,还是通过弹出来反转到第一个堆栈中。

【讨论】:

    【解决方案3】:

    addAll 只是添加所有项目的foreach 循环的便捷方法。除此之外,您真的无能为力:

    foreach(var item in stack2)
        stack1.Push(item);
    

    如果您特别频繁地这样做,您可以为其添加扩展方法,以方便您自己。

    【讨论】:

    • 是的,我现在看到那些 AddRange / AddAll 方法都进行迭代。我想我是为了方便而不是真正的表现。
    【解决方案4】:

    这不适用于当前的 .NET Stack 实现。

    为了将 Stack 的内容“嫁接”到另一个 Stack 的末尾,而不需要迭代其元素,内部实现详细说明了 Stack 类如何将它们存储在内存中。基于封装原则,这些信息“官方”只知道在 Stack 类本身内部。 .NET 的堆栈没有公开执行此操作的方法,因此如果不使用反射,就无法按照 OP 的要求执行此操作。

    可以想象,您可以使用反射将另一个 Stack 的内容附加到一个 Stack 的内部数组,并更新存储堆栈长度的字段,但这将高度依赖于 Stack 类的实现,可以在框架的未来版本,不会发出警告。

    如果你真的需要一个可以做到这一点的 Stack,你可以从头开始编写你自己的 Stack 类,或者简单地使用另一个集合,比如 ArrayListLinkedList ,它们有你想要的方法并添加 PushPop他们的扩展方法。

    【讨论】:

      猜你喜欢
      • 2020-04-03
      • 1970-01-01
      • 2012-02-15
      • 2019-08-08
      • 1970-01-01
      • 2022-10-17
      • 2019-04-26
      • 1970-01-01
      • 2015-01-14
      相关资源
      最近更新 更多