【问题标题】:Creating a fixed-size Stack创建固定大小的堆栈
【发布时间】:2011-12-05 09:19:55
【问题描述】:

我想在 Java 中创建一个堆栈,但要固定大小。例如,创建一个新堆栈,将大小设置为 10,然后当我将项目推送到堆栈时,它会填满,当它填满 10 时,堆栈中的最后一个项目被推开(移除)。我想使用 Stack,因为它使用 LIFO 并且非常适合我的需求。

但是 Stack 从 Vector 继承的 setSize() 方法似乎并没有真正限制 Stack 的大小。我想我错过了关于 Stacks 如何工作的一些东西,或者 Stacks 并不意味着受到限制,所以这是不可能的。请教育我!

【问题讨论】:

  • 仅供参考,setSize 方法是从 Vector 继承的,这意味着 setSize 将导致添加空值以填充提供的新大小,或者丢弃超出新大小的现有对象。理论上你可以通过 if (stack.size() >= 10) { stack.setSize(10); } 无论何时推送到堆栈,但最好实现自己的自定义类。
  • 我最初尝试这个只是为了看看它是否有效。这很奇怪,但似乎当我在堆栈上执行 setSize() 时,它会反转项目的顺序并从那里截断它们。所以我总是以堆栈中最初的 10 个项目结束。同样,另一种快速/肮脏的方法是 (stack.size() >= 10) { stack.remove(0);倒序时也会出现同样的问题,因此由于某种原因,0 索引是要删除的索引。
  • 这可能只是意味着底层实现实际上是这样工作的,堆栈方法以相反的顺序返回给你,无论如何这很有意义。
  • 好点,这可能正是正在发生的事情。
  • setSize() 表明 Stack 不是 Vector,而是应该包含 Vector,继承不是实现的正确决定。

标签: java stack


【解决方案1】:

您可以继承Stack 并覆盖适当的方法来实现此自定义行为。并确保给它一个清晰的名称(例如FixedStack)。

【讨论】:

    【解决方案2】:

    纯堆栈不会限制它的大小,因为堆栈解决的许多问题你不知道你需要多少元素。

    您可以编写一个自定义堆栈来实现您所描述的需求。但是,如果这样做,您将打破 LIFO。如果达到最大尺寸,并且您将新的东西压入堆栈,您只会丢失先前添加的项目。因此,如果您随后开始从堆栈中弹出项目,您会错过一些。

    【讨论】:

      【解决方案3】:

      您需要的是一个像LinkedList 这样的双端队列。虽然这不会自动将元素放在前面,但通过子类化/装饰它,您可以添加该功能。

      【讨论】:

        【解决方案4】:

        这不是不可能的 :) 你只需要提供你自己的实现。

        我会从像 this 这样的 RingBuffer 开始并相应地调整它。

        【讨论】:

          【解决方案5】:

          您可以像这样创建一个非常简单的堆栈:

          public class FixedStack<T>
          {
              private T[] stack;
              private int size;
              private int top;
          
              public FixedStack<T>(int size)
              {
                  this.stack = (T[]) new Object[size];
                  this.top = -1;
                  this.size = size;
              }
          
              public void push(T obj)
              {
                  if (top >= size)
                      throw new IndexOutOfBoundsException("Stack size = " + size);
                  stack[++top] = obj;
              }
          
              public T pop()
              {
                  if (top < 0) throw new IndexOutOfBoundsException();
                  T obj = stack[top--];
                  stack[top + 1] = null;
                  return obj;
              }
          
              public int size()
              {
                  return size;
              }
          
              public int elements()
              {
                  return top + 1;
              }
          }
          

          【讨论】:

          • 我最终做了类似的事情。谢谢!
          • 这里可能存在内存泄漏。
          • @mre:好的。坚持,稍等。我会修复的。完毕。这是你的意思吗?
          【解决方案6】:

          您可以使用 LinkedHashMap 并覆盖它的 removeEldestEntry 方法:

          public class FixedStack extends LinkedHashMap<Long, String> {
          
              private final int capacity;
          
              public FixedStack(int capacity) {
                  this.capacity = capacity;
              }
          
              @Override
              protected boolean removeEldestEntry(final Map.Entry<Long, String> eldest) {
                  return super.size() > capacity;
              }
          }
          

          并对其进行测试:

              public static void main(String[] args) {
          
                  FixedStack stack = new FixedStack(10);
          
                  long added = 0;
                  for (Locale locale : Locale.getAvailableLocales()) {
                      if (locale.getDisplayCountry().length() > 0) {
                          stack.put(added, locale.getDisplayCountry());
                          System.out.println(locale.getDisplayCountry());
                          added++;
                      }
                  }
                  System.out.println(String.format(">>>>>>>>> %s added",
                          added));
                  Iterator<Entry<Long, String>> iterator = stack.entrySet().iterator();
                  while (iterator.hasNext()) {
                      System.out.println(iterator.next().getValue());
                  }
              }
          

          您只需要决定要使用什么作为键,我在示例中使用了一个简单的计数器。

          【讨论】:

            【解决方案7】:

            这是一个扩展 StackSizedStack 类型:

            import java.util.Stack;
            
            public class SizedStack<T> extends Stack<T> {
                private int maxSize;
            
                public SizedStack(int size) {
                    super();
                    this.maxSize = size;
                }
            
                @Override
                public T push(T object) {
                    //If the stack is too big, remove elements until it's the right size.
                    while (this.size() >= maxSize) {
                        this.remove(0);
                    }
                    return super.push(object);
                }
            }
            

            像这样使用它:Stack&lt;Double&gt; mySizedStack = new SizedStack&lt;Double&gt;(10);。除了大小之外,它的运行方式与任何其他 Stack 一样。

            【讨论】:

            • 这太棒了!我建议将while (this.size() &gt; maxSize) 替换为if (this.size() == maxSize),以便将SizedStack 初始化为堆栈允许的实际最大大小。
            • 我将其更改为 while (this.size() &gt;= maxSize) 以处理您注意到的一个错误。谢谢。出于安全目的,它仍然应该是一个while循环;如果大小以某种方式大于 maxSize 会发生什么?我知道这似乎是不可能的,但错误就是错误:)。
            • 我喜欢支持您选择的体贴!好电话:D
            • 这是一个很好的答案,但值得一提的是,建议使用Deque 接口的实现,而不是(非常)旧的Stack,它不是线程安全的并且基于另一个不推荐使用的类,例如 Vector
            • Vector 未被弃用。它实现了List,实际上是同步的。 docs.oracle.com/javase/8/docs/api/java/util/Vector.html
            猜你喜欢
            • 2015-05-05
            • 1970-01-01
            • 2013-06-30
            • 2015-09-04
            • 2021-10-21
            • 2015-12-11
            • 2017-06-24
            • 2014-12-25
            • 2010-10-29
            相关资源
            最近更新 更多