哪种Collection类型最适合不断更新的固定大小的字符串数组?

时间:2015-05-19 11:28:38

标签: java android collections

我遇到过一种情况,我需要Android中的Collection类型,可以容纳String个对象并符合以下条件:

  • 它具有固定的大小(例如10)。
  • 只会从Collection
  • 的一端添加对象
  • 添加新对象时,所有其他对象会自动沿着一个空格进行随机播放以容纳它。
  • 如果Collection已满(所有10个空格已占用),则当从一端添加一个对象时,另一端的对象将被删除。
  • 可以随时在任一方向上迭代Collection的内容,并在每个位置检索对象。

根据我对收藏类型的体验,我觉得QueueLinkedList之类的东西是合适的,尽管我从来没有亲自使用过任何一种。但是,Android Docs中的一些术语让我对它们是否符合我的要求感到困惑。

例如,在Queue的文档中,声明:

  

队列通常但不一定按FIFO(先进先出)方式排序元素......

这听起来很理想,但当我考虑add()offer()方法时,它们都指定:

  

如果可以在不违反容量限制的情况下立即执行此操作,则将指定的元素插入此队列。

这听起来与我所追求的相反。

对于LinkedList,说明包括以下一行:

  

如果您需要类似队列的行为,则此类主要非常有用。

这是完美的,但稍后再次提到LinkedList在需要灵活尺寸时非常有用。

  

如果您希望列表包含零个或一个元素,但它仍然需要能够扩展到更大数量的元素,它也可能作为列表有用。

this tutorial site上:

  

链接列表的主要好处是您没有为列表指定固定大小。您添加到链中的元素越多,链就越大。

请有人能够澄清这些类型中的一种是否适合我的情况吗?

3 个答案:

答案 0 :(得分:3)

LinkedList肯定会奏效。 "添加"逻辑只是:

list.add(newItem);
if (list.size() > MAX_SIZE) {
    list.remove(0);
}

如果您需要超效率,String[MAX_SIZE]可能是合适的,current索引说明您在其中的位置(例如,环形缓冲区)。 "添加"逻辑是:

buffer[current] = newItem;
current = (current + 1) % MAX_SIZE;

最后一行移动到下一个位置,如有必要,再次回到0

假设您预先填充它(例如,它永远不会为空或部分为空),添加顺序的循环逻辑是:

for (int index = (current + 1) % MAX_SIZE; index != current; index = (index + 1) % MAX_SIZE) {
    // ...
}

如果它可能为空或部分为空,并且假设null不是有效的非空值,则您可以执行相同操作但跳过null。< / p>

答案 1 :(得分:1)

不要懒得自己动手吧!

public class Collection<T> implements Iterable<T>, RandomAccess{
    private final Object[] data;
    private int size = 0;

    public enum Direction{
        LEFT,
        RIGHT
    }

    private Direction direction = Direction.LEFT;

    public Collection(int capacity){
        data = new Object[capacity];
    }

    public void setDirection(Direction direction){
        this.direction = direction;
    }

    public void add(T item){
        if(size < data.length){
            switch (direction){
                case LEFT:
                    data[data.length - size] = item; 
                    break;
                case RIGHT:
                    data[size] = item;
                    break;
            }
            size++;
        }
        else {
            switch (direction) {
                case LEFT:
                    System.arraycopy(data, 1, data, 0, data.length - 1);
                    data[0] = item;
                    break;
                case RIGHT:
                    System.arraycopy(data, 1, data, 0, data.length - 1);
                    data[data.length - 1] = item;
                    break;
            }
        }
    }

    public void remove(){
        if(size == 0){
            return;
        }
        switch (direction){
            case LEFT:
                remove(data.length - size);
                break;
            case RIGHT:
                remove(size);
                break;
        }
    }

    public int size(){
        return size;
    }

    private void remove(int index) {
        System.arraycopy(data, index + 1, data, index, data.length - 1 - index);
        data[data.length - 1] = null;
    }


    @Override
    public Iterator<T> iterator() {
        return new Iterator<T>() {
            private int current = direction == Direction.RIGHT ? 0 : data.length - 1;

            @Override
            public boolean hasNext() {
                switch (direction){
                    case LEFT:
                        return current > 0;
                    case RIGHT:
                    default:
                        return current < data.length;
                }
            }

            @Override
            public T next() {
                current += direction == Direction.RIGHT ? 1 : -1;
                Object result = data[current];
                //noinspection unchecked
                return (T) result;
            }

            @Override
            public void remove() {
                Collection.this.remove(current + (direction == Direction.RIGHT ? -1 : 1));
            }
        };
    }
}

答案 2 :(得分:1)

有一个Collection几乎符合您的所有要求 - 这是ArrayDeque

不幸的是,它在一个方面不足以引用:

  

数组deques没有容量限制;他们根据需要增长以支持使用。

在好的方面:

  

当用作堆栈时,此类可能比Stack快,并且在用作队列时比LinkedList更快。

另外,如果你的设计基于现有的课程,那么犯错误的空间就会减少。

那么,在添加元素时,如何将ArrayDeque行为更改为不调整大小,而是抛弃旧元素?简单 - 所有添加都采用以下两种方法之一:addFirst(E e)addLast(E e)。这些方法是公开的,因此可以覆盖。

因此,我向您展示了一个未调整大小的ArrayDeque版本:

private final int maxSize;
public MyArrayDeque(int maxSize) {
    super(maxSize);
    this.maxSize= maxSize;
}

@Override
public void addFirst(E e) {
    if (maxSize == size()) 
        removeLast();
    super.addFirst(e);
}

@Override
public void addLast(E e) {
    if (maxSize == size()) 
        removeFirst();
    super.addLast(e);
}

就是这样。当然,您还应该修改clone()的行为和序列化方法,如果您想要非常彻底,那么也应该如此,但对于大多数用例来说,这是可选的。另外,不要将此代码显示给任何OOP纯粹主义者,这不是很好用于继承=)

如果您正在努力提高性能,您可能希望实际复制该类中的代码并进行就地修改。这将允许您在无法调整大小时删除多个冗余的检查和方法。它还允许更快的for循环而不创建Iterator(通过简单地获取Iterator中的代码 - 它与@TJ Crowder的版本精神接近,但是使用按位运算符,因为数组是2长度的力量。)