我遇到过一种情况,我需要Android中的Collection
类型,可以容纳String
个对象并符合以下条件:
10
)。Collection
Collection
已满(所有10
个空格已占用),则当从一端添加一个对象时,另一端的对象将被删除。Collection
的内容,并在每个位置检索对象。 根据我对收藏类型的体验,我觉得Queue
或LinkedList
之类的东西是合适的,尽管我从来没有亲自使用过任何一种。但是,Android Docs中的一些术语让我对它们是否符合我的要求感到困惑。
例如,在Queue的文档中,声明:
队列通常但不一定按FIFO(先进先出)方式排序元素......
这听起来很理想,但当我考虑add()
和offer()
方法时,它们都指定:
如果可以在不违反容量限制的情况下立即执行此操作,则将指定的元素插入此队列。
这听起来与我所追求的相反。
对于LinkedList,说明包括以下一行:
如果您需要类似队列的行为,则此类主要非常有用。
这是完美的,但稍后再次提到LinkedList
在需要灵活尺寸时非常有用。
如果您希望列表包含零个或一个元素,但它仍然需要能够扩展到更大数量的元素,它也可能作为列表有用。
链接列表的主要好处是您没有为列表指定固定大小。您添加到链中的元素越多,链就越大。
请有人能够澄清这些类型中的一种是否适合我的情况吗?
答案 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长度的力量。)