【问题标题】:List with max elements具有最大元素的列表
【发布时间】:2013-09-28 07:14:42
【问题描述】:

我想在 java 中创建一个列表,在添加新元素时,将检查是否达到限制。如果是,请删除最旧的元素。

我正在考虑创建 ArrayList 的子级并覆盖 add(Object)。在那里我会这样做:

if(size() + 1 > MAX)
    remove(get(0));
super.add(newObject);

有更好的方法吗?

【问题讨论】:

  • 这不是一个好主意。删除ArrayList 的第一个元素会导致所有其他元素移动(这需要O(n) 时间)。您应该改用圆形数组。
  • 除了 jazzbassrob 的回答之外,article 可能会引起您的兴趣。另见SO question
  • 像其他人建议的那样,使用循环数组。但作为一般规则,我更喜欢组合而不是继承,它允许使用装饰器模式。因此,如果我想使用列表,我宁愿为列表创建一个装饰器类,它强制执行最大大小(从而允许装饰器的用户在 ArrayList 和 LinkedList 甚至其他列表之间进行选择),而不是创建 ArrayList 的子类或链表。

标签: java list arraylist


【解决方案1】:

你描述的是一个循环先进先出缓冲区。您可以使用 Apache Commons-collections 实现。

有关文档,请参阅 Commons CollectionsCircularFifoBuffer

【讨论】:

    【解决方案2】:

    创建自己的类来完成这项工作。跟踪两个变量。一个代表零元素,一个代表下一个元素的位置。

    public class MyList<T>
    {
        private T array[];
        private int first;
        private int next;
        private int count;
    
        public MyList(int count)
        {
            array = new T[count];
        }
    
        public void add(T obj)
        {
            array[next++] = obj;
            next %= array.length;
            if (count == array.length)
            {
                zero = (zero + 1) % array.length;
            } else count++;
        }
    
        public T get(int index)
        {
            return array[(zero + index) % array.length];
        }
    }
    

    【讨论】:

      【解决方案3】:

      你可以使用Deque:

      private final int LIMIT = 10;
      
      private Deque<String> queue = new ArrayDeque<String>(LIMIT);
      
      public void addToList(final String element) {
         Deque<String> queue = new ArrayDeque<String>(LIMIT);
         if (!queue.offer(element)) {
            queue.removeFirst();
            queue.offer(element);
         }
      }
      

      【讨论】:

        【解决方案4】:

        IMO,您应该使用带有列表包装器的数组。然后你可以做任何你想做的事情。您还可以添加方法,例如获取返回一个列表。

        【讨论】:

          【解决方案5】:

          您可以按照您描述的方式进行操作,但这样的列表的性能会很低。想象一下已经达到了限制,并且您删除了第一个元素。在幕后,这将涉及将底层数组的所有元素向上复制一个索引。然后将新元素添加到最后一个索引。尤其是所有元素的复制成本很高

          您也可以使用LinkedList,这对于此类操作更有效。

          另一种方法是编写自己的类来实现Circular Buffer。 这基本上是一个大小为 MAX 的数组。您必须保留第一个元素的索引和数组中的元素数。添加元素时,检查元素的数量是否等于 MAX,如果是,则覆盖第一个元素并将第一个元素的索引增加一。 索引的 getter 和 setter 也需要考虑第一个元素的偏移量,但这并不过分复杂。

          最佳选择取决于您的用例。如果您必须在列表中的随机位置进行大量插入和删除操作,LinkedList 绝对是您的最佳选择。如果只想将项目添加到末尾并移除头部,则循环缓冲区非常有效。

          【讨论】:

            【解决方案6】:

            对此可能有多种解决方案,但我认为如果您进行一个更改,您的方法是一种合适的方法:您的底层实现类应该是LinkedList,而不是ArrayList。原因是,当您在 ArrayList 上调用 remove 时,删除值之后的每个元素都必须向上移动(使 remove(0) 成为最坏的情况!)。不过这对于LinkedList 来说不是问题。

            【讨论】:

            猜你喜欢
            • 2012-11-12
            • 1970-01-01
            • 1970-01-01
            • 2023-03-15
            • 1970-01-01
            • 2016-10-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多